Exercícios — Interfaces e o Contrato de Comportamento
Aula 6 — Programação Orientada a Objetos
Marcos M. Raimundo — Instituto de Computação, UNICAMP
Questões discursivas
Explique o conceito de Interface como um “Contrato de Comportamento” e comente por que ela representa a materialização máxima do paradigma da Caixa Preta. O que diferencia a tipagem pura de uma interface da tipagem baseada em herança de classes?
Analise a técnica do “Mutador Cego”. Como uma interface moderna consegue orquestrar a alteração do saldo de uma conta (aplicar juros), se ela é estritamente proibida de possuir atributos de instância? Explique usando a ideia de inversão de conhecimento (cérebro vs. músculos).
Explique por que o sistema de tipos estáticos do Java (garantir que um parâmetro seja
double) é insuficiente para proteger a integridade das regras de negócio. Como o lançamento de exceções atua como fiscalizador do contrato quando os limites da tipagem são atingidos?
Questões de Verdadeiro/Falso
Cada bloco de 4 itens trata do mesmo tema. A questão só é considerada correta se todos os 4 itens forem julgados corretamente (deixar em branco tem penalidade de 20% da nota da questão).
- □ Numa interface
Voadorusada tanto por uma classePassaroquanto por uma classeDrone, o contrato exige apenas o métodovoar()— nada nele obriga as duas classes a compartilharem qualquer atributo interno. - □ Métodos de interface, em Java, terminam com corpo de implementação obrigatório.
- □ Se uma classe implementasse apenas dois dos três métodos declarados por uma interface, deixando o terceiro sem corpo e sem a própria classe ser declarada
abstract, o código ainda compilaria normalmente, desde que@Overrideestivesse presente nos dois métodos implementados. - □ No limite em que a anotação
@Overrideé removida de um método que de fato sobrescreve um método da interface, o comportamento em tempo de execução (qual método é chamado) muda.
- □ A interface é chamada de “Tipo Puro” porque não impõe hierarquia de herança de estrutura.
- □ Duas classes de famílias completamente diferentes podem compartilhar o mesmo tipo, desde que implementem a mesma interface.
- □ Numa aplicação que precisa que tanto uma classe
VeiculoEletricoquanto uma classeGerador(duas famílias completamente diferentes de objetos) sejam tratadas comoRecarregavel, implementar uma interface comum resolveria isso sem exigir que ambas compartilhem uma superclasse. - □ Herança de classe e implementação de interface são exatamente o mesmo mecanismo em Java.
- □ Se, em vez de usar
default, a nova funcionalidadeprocessarComLogfosse adicionada como um método abstrato comum na interfacePagavel, todas as classes existentes que já implementamPagavel(comoPix) continuariam compilando sem nenhuma alteração. - □ No limite em que uma interface só contém métodos
static(nenhum método abstrato, nenhumdefault), ainda seria possível instanciar essa interface diretamente comnew, já que ela não teria mais nenhum método pendente de implementação. - □ Métodos
privateem interfaces (Java 9+) servem para compartilhar lógica auxiliar entre métodosdefault. - □ A introdução de
default methodsobriga todas as classes legadas a serem recompiladas e alteradas manualmente.
- □ Uma interface pode orquestrar transições de estado, mesmo sem possuir atributos de instância próprios.
- □ Numa interface
ValidadorDeSenhacom um métododefault validar()que aplica regras de comprimento e complexidade chamandogetSenhaAtual()(abstrato), a classe concreta que armazena a senha real desempenha o papel dos “músculos”, enquanto a interface continua sendo o “cérebro” da regra. - □ O método
default aplicarJurossabe exatamente onde e como o saldo está fisicamente armazenado. - □ No limite em que só existe uma única classe implementando
Pagavelem todo o sistema, centralizaraplicarJuroscomodefaultna interface, em vez de deixá-lo como método comum daquela única classe, ainda traria o mesmo ganho de evitar duplicação de código.
- □ Se uma interface Java declarasse um atributo
public static final int LIMITE = 10, isso contradiria a regra de que interfaces não podem ter estado. - □ Numa aplicação de jogos em que uma classe
PersonagemVoadorprecisa herdar atributos físicos comuns de uma classe abstrataPersonageme, ao mesmo tempo, prometer comportamentos deVoadore deNadador, ela pode declararextends Personagem implements Voador, Nadadorna mesma linha. - □ Interfaces definem uma identidade (“o que é”); classes abstratas definem um papel (“o que faz”).
- □ Num sistema bancário em que
ContaCorrenteeContaPoupancacompartilham o atributo protegidosaldoe a lógica de validação de saque, mas cada uma tem regras de rendimento completamente diferentes, uma classe abstrataContaBancaria(não uma interface) é a ferramenta mais adequada para compartilhar esse estado protegido.
- □ O tipo de um objeto orientado a objetos é definido pelas mensagens às quais ele responde, não pelo que ele guarda.
- □ Numa hierarquia de coleções,
ArrayListeHashMapnão compartilham nenhuma superclasse de dados em comum além deObject, mas ambas poderiam implementar uma interfaceLimpavelcom um métodolimpar(), tornando-as do mesmo tipoLimpavelpara quem só precisa chamar esse método. - □ Declarar uma variável como
Pagavelinforma ao compilador exatamente qual classe concreta ela contém. - □ Se o
CheckoutControllerdeclarasse a variávelformaEscolhidacomoPixem vez dePagavel, mesmo que hoje sóPixfosse usado na prática, isso já eliminaria a vantagem de programar para a abstração caso umCripto implements Pagavelsurgisse amanhã.
- □ No limite em que o parâmetro fosse declarado como um tipo customizado
ValorMonetario(em vez dedoubleprimitivo) que só pudesse ser construído com valores positivos, a validação de negócio migraria do corpo do método para o próprio sistema de tipos, em tempo de compilação. - □ Um preço negativo passado para
criarCobranca(double valor)é rejeitado automaticamente pelo compilador. - □ Num sistema de reservas de voos que aceita um parâmetro
int quantidadeAssentos, um valor negativo passa a validação de tipo do compilador da mesma forma que um valor positivo — a mesma lacuna do sistema de tipos vista para o valor de pagamento desta aula se repete aqui. - □ Uma exceção é uma forma de o objeto dizer “recebi o tipo certo, mas os dados violam minhas regras”.
- □ Retornar
null,0oufalsepara sinalizar erro é uma boa prática recomendada nesta aula. - □ Se, em vez de lançar a exceção imediatamente ao detectar
valor <= 0, o métodocriarCobrancaapenas registrasse o erro num log interno e continuasse a execução normalmente até o fim, isso ainda seria uma aplicação válida da filosofia Fail-Fast. - □ Falhas silenciosas tendem a se manifestar mais tarde, em pontos distantes da causa raiz do problema.
- □ Lançar uma exceção no ponto exato da violação facilita o rastreamento via stack trace.
- □ O bloco
try-catchnoCheckoutControllerprotege a experiência do usuário contra falhas de baixo nível. - □ Segundo a diretriz desta aula, componentes de baixo nível devem capturar e silenciar suas próprias exceções.
- □ No limite em que não existe nenhum componente de alto nível entre o objeto que lança a exceção e o usuário final (a exceção se propaga direto até a interface), a aplicação da diretriz desta aula ainda garantiria uma mensagem de erro tratada e amigável para o usuário.
- □ Um
catchbem posicionado evita que uma falha externa (rede, banco) derrube o fluxo principal do sistema.
- □ Numa aplicação de streaming de vídeo que hoje só grava logs de erro em arquivo local, trocar para uma interface
Logavelimplementada por um adaptador de nuvem seguiria a mesma lógica deNotificavel: o consumidor do log não precisa mudar uma linha. - □ Um
double descontoisolado, sem uma interfaceEstrategiaDesconto, já protege contra valores absurdos como 500%. - □ Se, em vez de uma interface
ServicoLogistico, oPedidochamasse diretamente uma classe concretaTransportadoraCorreiospara gerar o código de rastreio, trocar de transportadora no futuro não exigiria nenhuma alteração emPedido. - □ No limite em que um método de interface declara
throws Exception(a superclasse mais genérica possível) em vez de uma exceção específica comoCarrierUnavailableException, a cláusula do contrato continua igualmente informativa sobre como e por que o método pode falhar.
- □ Numa API de pagamento internacional que declara
throws CurrencyConversionException, isso avisa ao consumidor da API que a conversão de moeda pode falhar por fatores fora do controle do próprio método (ex.: serviço de cotação indisponível), da mesma forma quecriarCobrancaavisa sobre falhas de validação. - □ Se um método lançasse uma exceção apenas para simular uma falha que nunca ocorre de fato na prática, isso ainda seria consistente com a ideia de exceção como “honestidade sobre um risco real”.
- □ Num sistema de pagamento que, ao receber uma
IllegalArgumentExceptionde um valor inválido, registra o erro, notifica o usuário e continua processando os próximos pedidos da fila sem interromper o serviço inteiro, isso demonstra o mesmo ato de resiliência descrito nesta aula para o tratamento de exceções. - □ Uma vez capturada, uma exceção deve sempre ser ignorada silenciosamente para não incomodar o usuário.
- □ No limite em que
Pedidodependesse de dez interfaces diferentes em vez de três, o princípio de quePedido“não sabe como”, só “confia no contrato”, deixaria de valer, porque o número de dependências já seria alto demais para manter esse desacoplamento. - □ Se
EstrategiaDescontonão declarassethrowsnem lançasse nenhuma exceção em caso de valor inválido, apenas retornando0(desconto nulo) silenciosamente,Pedidoainda estaria recebendo a mesma garantia de honestidade do contrato que as demais interfaces desta aula oferecem. - □ Programar contra interfaces e proteger regras com exceções são práticas independentes, sem relação entre si.
- □ Esse design permite trocar implementações concretas em tempo de execução sem alterar o núcleo do sistema.