Soluções — Composição de Sistemas: Contratos e Estabilidade
Aula 3 — Programação Orientada a Objetos
Dica(Resposta) Teste 1 — Do Fabricante ao Arquiteto
- ✗ Falso — A aula argumenta exatamente o contrário: peças perfeitas isoladamente (alta qualidade interna) que não se encaixam bem são “o caminho mais rápido para o fracasso”. A sustentabilidade de um sistema depende de como os objetos colaboram (mensagens, contratos), não apenas da qualidade interna de cada classe tomada isoladamente.
- ✗ Falso — Expor dados livremente é o oposto do “arquiteto de sistemas” descrito na aula — é a intimidade técnica/acoplamento por “fofoca” que o design por contratos busca eliminar. Um sistema robusto é uma rede de colaboradores especializados que se comunicam por mensagens, não um amontoado de estruturas de dados abertas.
- ✔ Verdadeiro — É o benefício direto da separação interface/implementação transferido para o processo de design: ao definir primeiro os encaixes (contratos) entre as peças, o arquiteto desenha a estrutura do sistema sem precisar fixar, naquele momento, os detalhes de implementação de cada classe — esses detalhes ficam encapsulados e podem ser definidos depois.
- ✔ Verdadeiro — É a essência do salto de “fabricante de peças” para “arquiteto de sistemas”: pensar primeiro em quem fala com quem e o que cada mensagem promete (o contrato) evita desenhar classes que sabem demais sobre os vizinhos; a lógica interna é um detalhe de implementação que pode evoluir livremente depois que o contrato está definido.
Dica(Resposta) Teste 2 — Colaboração e Baixo Acoplamento
- ✔ Verdadeiro — No exemplo
Produto/ItemCarrinho/Carrinho,Produtoé inteiramente autônomo e não conheceCarrinhonem nenhuma interface de usuário — essa é a definição de baixo acoplamento: o especialista deve servir a qualquer orquestrador (vitrine, estoque, relatório fiscal) sem sequer saber quem o está usando. - ✗ Falso — Isso violaria o encapsulamento estudado nas Aulas 1-2. No código da aula,
ItemCarrinho“pergunta” ao produto viagetPreco(), nunca acessaprecoBasediretamente — perguntar via método é o que permite aoProdutomudar sua implementação interna sem quebrarItemCarrinho. - ✔ Verdadeiro —
calcularTotal()apenas percorre a lista e chamaitem.subtotal()— ele orquestra, mas não sabe como o subtotal é calculado internamente; confia apenas no contrato de que existe um métodosubtotal(). - ✔ Verdadeiro — A aula argumenta que concentrar toda a inteligência numa única classe “gerente” é o erro do Modelo Anêmico em escala de sistema; dividir em
Produto/ItemCarrinho/Carrinhoespecialistas é exatamente o que evita que uma única classe cresça sem limite (o Objeto Deus) e permite testar cada peça isoladamente.
Dica(Resposta) Teste 3 — Interface como Contrato
- ✗ Falso — Bugs na implementação são um problema de qualidade/correção do código interno, não uma quebra da fronteira interface/implementação. Essa fronteira “falha” quando o cliente precisa conhecer o “como” para usar ou contornar o problema — se
Compracontinua chamando sóisValido()sem precisar saber da lógica interna, a fronteira permanece intacta mesmo havendo um bug a corrigir. - ✔ Verdadeiro — É o argumento central do bloco:
Compraé agnóstica quanto à complexidade deisValido(); trocar o algoritmo de validação por outro (ou o gateway por REST/gRPC) não exige queCompraseja recompilada, pois a assinatura pública permanece idêntica. - ✔ Verdadeiro — A aula identifica exatamente essa falha como a mais recorrente em sistemas complexos: quando a fronteira interface/implementação é rompida, uma mudança de baixo nível provoca falhas em cascata em módulos que não deveriam nem saber que a troca aconteceu.
- ✗ Falso — É o oposto do que a aula defende — uma boa interface expõe o mínimo necessário (o “Quê”), escondendo a estrutura interna (o “Como”). Expor estrutura interna aumenta o acoplamento físico e a fragilidade; não é isso que viabiliza reuso seguro.
Dica(Resposta) Teste 4 — Design de Caixa Preta
- ✔ Verdadeiro — É o mecanismo do encapsulamento (herdado das Aulas 1-2) aplicado aqui: com
precoCustoprivado, qualquer interação comProdutosó pode passar pelos métodos públicos, comocalcularPrecoDeVenda(). - ✔ Verdadeiro — É exatamente a prova apresentada com
calcularPrecoDeVenda(): a fórmula de margem mudou drasticamente da V1 para a V2 (incluindo um limiar de preço), mas como o contrato (assinatura) permaneceu o mesmo, o impacto no resto do sistema foi zero. - ✗ Falso — Isso confia na disciplina do programador em vez de no compilador/design — exatamente o tipo de risco que o encapsulamento existe para eliminar estruturalmente. “Confiar que ninguém vai usar errado” não escala à medida que o sistema cresce e não é uma alternativa válida à proteção real do estado.
- ✔ Verdadeiro — É a demonstração central do bloco — a V2 mudou a lógica (limiar de R$ 1000, duas margens diferentes) mas manteve a mesma assinatura pública, então nenhum código cliente precisou mudar.
Dica(Resposta) Teste 5 — A Lei de Demeter
- ✗ Falso — O ganho de Demeter num método de delegação está em devolver o resultado já processado (um booleano, um CEP), não em ainda expor um objeto interno para navegação. Se
getCEPDeEntrega()devolvesseEndereco, o chamador voltaria a fazer.get().get(), recriando o próprio “naufrágio de código” que a delegação deveria eliminar. - ✔ Verdadeiro — É a motivação da lei: cada ponto extra numa cadeia como
pedido.getCliente().getCarteira().getSaldo()é uma promessa de que o código vai quebrar quando a estrutura intermediária mudar — Demeter contém esse espalhamento de conhecimento estrutural. - ✗ Falso — É o oposto — “falar com estranhos” é a própria definição da violação (o “naufrágio de código”); aumenta a fragilidade, pois qualquer mudança na estrutura intermediária (como troca de
Carteirapor ApplePay) quebra o código que a atravessou diretamente. - ✔ Verdadeiro — É exatamente a “cura” apresentada — delegação em cadeia guiada por Tell, Don’t Ask, em que o objeto que detém os dados internos responde à pergunta certa por fora, sem que o chamador precise navegar pela estrutura interna.
Dica(Resposta) Teste 6 — O Naufrágio de Código (Train Wreck)
- ✔ Verdadeiro — É a assinatura visual do problema apresentada na aula, como em
pedido.getCliente().getCarteira().getSaldo()— uma cadeia de.get()atravessando várias fronteiras de objeto. - ✗ Falso — A aula é explícita: “o problema não é a quantidade de pontos — é a invasão de fronteiras”; o risco é estrutural (fragilidade a mudanças na estrutura intermediária), não estético (legibilidade).
- ✔ Verdadeiro — Cada
.get()na cadeia atravessa a fronteira de um objeto diferente que não é “amigo próximo” de quem originou a chamada — exatamente a violação que a Lei de Demeter proíbe. - ✔ Verdadeiro — É a consequência prática destacada no exemplo do ApplePay: se
Checkoutnavegasse atéCarteiradiretamente, trocar a carteira física por um aplicativo quebraria esse código; com delegação (Checkoutfica cego para a existência deCarteira), o código permanece intocado.
Dica(Resposta) Teste 7 — Tell, Don’t Ask na Prática
- ✔ Verdadeiro — É o padrão
pedido.clientePodePagar()do bloco: em vez de sondar (Ask) o saldo por fora, o chamador dá um comando/pergunta de alto nível (Tell) ao objeto que sabe como resolver isso internamente. - ✗ Falso — É o oposto — “perguntar” por dados para decidir por fora é a prática Ask que a aula associa à violação de Demeter e ao Feature Envy; decidir por fora com dados de outro objeto enfraquece o encapsulamento, não o fortalece.
- ✔ Verdadeiro — É a cura apresentada para Feature Envy — mover o comportamento para a classe que detém o dado evita que uma classe externa precise “espiar” e operar sobre dados que não são seus.
- ✔ Verdadeiro — O chamador (
Checkout) apenas invocaclientePodePagar()e recebe uma resposta; toda a lógica de como verificar o saldo (delegando aoCliente) fica encapsulada dentro dePedido— o chamador nunca “pergunta” pelos dados brutos.
Dica(Resposta) Teste 8 — Delegação e Feature Envy
- ✗ Falso — Chamar um método de um colaborador direto (um atributo próprio, um “amigo”) não é violação — é exatamente a definição de delegação em cadeia usada em
Carrinho.calcularTotal()e emPedido.clientePodePagar(). A violação ocorreria seFuncionarionavegasse além deDepartamento(ex.:this.departamento.getEmpresa().getTabela()...), atravessando uma fronteira que não é a de um amigo direto. - ✗ Falso — É o oposto do design apresentado —
Carrinhonão calcula nada sozinho, ele delega a cadaItemCarrinhoo cálculo do próprio subtotal; fazer isso “pessoalmente” recriaria acoplamento e um Objeto Deus, sem qualquer ganho real de precisão. - ✔ Verdadeiro — É a própria definição do code smell apresentada na aula, associada ao naufrágio de código (
getCliente().getCarteira().getSaldo()). - ✔ Verdadeiro — É exatamente a cura descrita — “mover o comportamento para onde os dados residem” — que resulta em métodos de delegação como
clientePodePagar().
Dica(Resposta) Teste 9 — Programar para Abstrações
- ✗ Falso — É o oposto do argumento da aula — programar para a interface aumenta a flexibilidade (Plug-and-Play), permitindo que
Pixseja adicionado sem alterarCheckout; é programar para o tipo concreto que aumenta a rigidez, como mostra o erro de compilação do exemplo. - ✔ Verdadeiro — É a demonstração central do bloco:
Checkout.finalizar(Pagavel metodo)aceitaBoleto,CartaoDeCreditoe, no futuro,Pix, sem qualquer alteração no código deCheckout. - ✔ Verdadeiro — É a analogia do “padrão USB-C” da aula — um encaixe universal, indiferente à identidade concreta de quem o implementa, é o que torna sistemas flexíveis e extensíveis.
- ✔ Verdadeiro — É o próprio benefício do Plug-and-Play demonstrado: assim que
Pix implements Pagavelexistir,Checkout.finalizar(Pagavel)já sabe processá-lo, sem recompilação.
Dica(Resposta) Teste 10 — O Erro de Tipagem como Diagnóstico
- ✗ Falso — A aula é explícita: esse erro “não é só uma falha sintática — é um diagnóstico de acoplamento forte”; o compilador está corretamente reportando uma limitação de design, não cometendo um bug.
- ✔ Verdadeiro — É exatamente a leitura proposta pela aula: o erro mostra que o parâmetro exige a classe
CartaoDeCreditoespecificamente, quando deveria exigir apenas a capacidade deisPagamentoValido(). - ✔ Verdadeiro — É a solução apresentada — trocar o parâmetro de
CartaoDeCreditoparaPagavel, que ambas as classes (e futuras) podem implementar. - ✔ Verdadeiro — É a conclusão do bloco anterior aplicada aqui: ao depender de
Pagavelem vez de uma classe concreta,Checkoutdeixa de conhecer detalhes de qualquer meio de pagamento específico.
Dica(Resposta) Teste 11 — Custo de Mudança e o Princípio TRUE
- ✗ Falso — “Razoável” mede a relação entre o custo de uma mudança e o benefício/escala da própria mudança, não o tamanho acumulado do código já existente. Um custo que cresce com o tamanho total do sistema (em vez de com a complexidade da mudança em si) é sintoma de acoplamento alto — documentação não substitui contratos estáveis e baixo acoplamento como solução real para esse problema.
- ✔ Verdadeiro — É a definição de “Razoável” dentro do princípio TRUE — o custo de implementar algo não deveria ser desproporcional ao valor que essa mudança entrega.
- ✗ Falso — É o oposto — o design de caixa preta (interface estável, implementação oculta) reduz o custo de mudança, permitindo que a implementação evolua sem efeito cascata. “Esconder erros” confunde ocultar detalhes de implementação com mascarar bugs, que são coisas diferentes.
- ✔ Verdadeiro — É a tese geral da aula: quando cada objeto conhece apenas o contrato de seus colaboradores, adicionar ou trocar peças (como um novo
Pagavel) não exige tocar em cascata em outras partes do sistema, mantendo o custo de mudança controlado.
Dica(Resposta) Teste 12 — O Papel do Orquestrador
- ✔ Verdadeiro — É a metáfora central do bloco de colaboração —
Carrinho.calcularTotal()orquestra chamandoitem.subtotal()de cadaItemCarrinho, sem calcular preços ou impostos por conta própria. - ✔ Verdadeiro — É exatamente o que o código de
calcularTotal()faz — soma os valores retornados poritem.subtotal(), sem recalcular ou acessar os dados internos deItemCarrinho. - ✗ Falso — É exatamente o que o design por contrato evita — enquanto
ItemCarrinho.subtotal()mantiver a mesma assinatura,Carrinhonão precisa saber nem se importar com como o subtotal é calculado internamente; é o mesmo argumento de estabilidade de contrato do bloco “Design de Caixa Preta”. - ✔ Verdadeiro — É a consequência direta de depender de contratos (o “O Quê”) em vez de implementações (o “Como”) — o orquestrador só é afetado se a assinatura do contrato mudar, não quando a lógica interna do especialista evolui.