Exercícios — Acoplamento e Contratos
Aula 5 — Programação Orientada a Objetos
Marcos M. Raimundo — Instituto de Computação, UNICAMP
Questões discursivas
Explique por que a separação de código em arquivos diferentes e o uso de construtores não são, por si só, garantia de desacoplamento. Diferencie acoplamento físico de acoplamento lógico, usando o exemplo de
PedidoeCarrinho.Entre a classe
Pedidoe a classeCarrinho, qual deveria calcular o valor total da compra, segundo o princípio GRASP do Especialista na Informação? Justifique com base em quem possui os dados necessários.O que significa dizer que “módulos de alto nível não devem depender de módulos de baixo nível”? Explique como criar uma interface
Pagavelinverte a dependência entreClienteeCartao.
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).
- □ O acoplamento físico (separação em arquivos) garante, por si só, o desacoplamento lógico entre classes.
- □ Numa classe
RelatorioFinanceiroque recebe umCarrinhopelo construtor e itera diretamente sobre seus itens internos para somar valores, a mesma falha de Feature Envy desta aula se aplica, mesmo em um contexto de relatório, não de pedido. - □ O paradigma da Caixa Preta permite acessar os dados internos de um colaborador associado, desde que via getter.
- □ Ter a referência de um objeto não dá o direito de processar seus dados internos por fora dele.
- □ No limite em que um método usa um único getter de um colaborador, uma única vez, para uma leitura simples e isolada, isso já caracteriza Feature Envy com a mesma severidade do exemplo de
calcularCustoTotal()desta aula. - □ O sintoma clássico é o uso repetitivo de getters de um colaborador para processar dados externamente.
- □ Se, em vez de mover a lógica de soma para o
Carrinho(Move Method), apenas renomeássemos o métodocalcularCustoTotal()parasomarItensExternamente(), o Feature Envy estaria resolvido. - □ Feature Envy não tem relação nenhuma com o princípio “Tell, Don’t Ask”.
- □ No limite em que uma classe depende de uma única classe externa, mas invoca dezenas de métodos diferentes dela, o CBO dessa classe continua sendo 1, independentemente do número de chamadas.
- □ Refatorar de Feature Envy para delegação pura tende a reduzir o CBO da classe orquestradora.
- □ Manter o CBO baixo reduz o risco de Efeito Cascata e facilita testes isolados.
- □ O objetivo ideal de qualquer design é atingir CBO igual a zero.
- □ Se o atributo
itensdoCarrinhofosse declaradoprivateem vez depublic, o métodoaplicarDescontoManualdePedidoainda conseguiria fazerc.itens.clear()diretamente, sem nenhuma mudança adicional de design. - □ Atributos
publicfavorecem diretamente o Acoplamento de Conteúdo. - □ O Acoplamento Comum via métodos estáticos facilita a substituição por mocks em testes automatizados.
- □ Uma chamada estática oculta no corpo de um método é uma dependência mais difícil de enxergar do que uma no construtor.
- □ Num sistema de RH que passa um objeto
Funcionariointeiro para um método que só precisa calcular o desconto do INSS a partir do salário, isso é o mesmo padrão de Acoplamento de Estampa visto no exemplo deNotificacaoEmail/Clientedesta aula. - □ Renomear a classe passada por Estampa pode quebrar o receptor, mesmo sem mudança na lógica de negócio.
- □ No limite em que um serviço
Notificacaorecebe cada vez mais parâmetros primitivos individuais (não um objeto), manter o Acoplamento de Dados se torna, na prática, cada vez mais difícil de gerenciar, mesmo sem nenhuma perda de reutilização. - □ Refatorar de Estampa para Dados torna o serviço menos reutilizável, pois perde contexto.
- □ Se duas classes,
PedidoeCliente, tivessem acesso igual aos dados de endereço de entrega, masClientefosse quem originalmente recebe esse dado do usuário, o GRASP recomendaria colocar a lógica de validação de endereço emPedido, e não emCliente. - □ Segundo o GRASP, o
Pedidodeveria calcular o total, já que ele “contém” oCarrinho. - □ Num sistema onde o cálculo de imposto de um
Produtoestá espalhado em três classes diferentes que só “pegam” o preço via getter, aplicar o Especialista na Informação implicaria mover essa lógica para dentro da própria classeProduto. - □ No limite em que uma única classe do sistema concentra toda a informação de todos os domínios de negócio, o GRASP do Especialista na Informação recomendaria centralizar ainda mais responsabilidades nela, já que ela já detém os dados.
- □
Clientecomprivate Cartao cartaoacoplado a uma classe concreta é um exemplo do limite da composição básica. - □ Adicionar
PixeBoletocomo novos atributos opcionais emCliente, comif/else, respeita o OCP. - □ A explosão de complexidade ciclomática por
if/elseé um sintoma de acoplamento a classes concretas. - □ O acoplamento a implementações concretas impede a extensão Plug-and-Play do sistema.
- □ Se, em vez de uma interface
Pagavel,Clientedependesse de uma classe abstrataFormaDePagamentoAbstratacom métodos concretos parciais, isso ainda seria uma aplicação válida do DIP, desde queClientenão referenciasseCartaoouPixdiretamente. - □ Abstrações devem depender dos detalhes técnicos das implementações concretas.
- □ O DIP permite erguer um “Muro de Fronteira” entre o núcleo do negócio e a infraestrutura.
- □ Se, em vez de depender de
Pagavel,Clientecontinuasse com um único atributoCartao cartao, mas todo acesso a ele passasse por blocostry/catchgenéricos, isso já seria suficiente para dizer queClienteaplicou o DIP.
- □ No limite em que um sistema nunca precisa de nenhuma extensão futura (o conjunto de comportamentos é fixo para sempre), a distinção entre respeitar ou violar o Princípio Aberto/Fechado deixa de ter qualquer consequência prática.
- □ A cadeia de
if/elsesobre tipos concretos de pagamento é compatível com o OCP. - □ Depender de uma interface como
Pagavel, em vez de classes concretas, favorece o cumprimento do OCP. - □ O DIP e o OCP trabalham juntos: abstrações estáveis permitem estender o sistema sem modificar o núcleo.
- □ Em Java, uma variável do tipo
Pagavelpode referenciarPixouCartao, desde que ambos implementem o contrato. - □ A composição pura, sem nenhum mecanismo de contrato, já é suficiente para essa substituição em tempo de execução.
- □ Num sistema escrito numa linguagem de tipagem dinâmica, como Python sem type hints, a mesma capacidade de aceitar
PixouCartaoatravés de uma única variável existiria por duck typing, sem nenhum mecanismo de contrato exigido em tempo de compilação. - □ No limite em que existisse só uma única forma de pagamento em todo o sistema (sem
Pix,Boletoou futuros métodos), a necessidade de Polimorfismo para resolver o problema de “múltiplas identidades” desapareceria por completo.
- □ Se a lógica de soma do carrinho estivesse centralizada num único método de uma única classe (Move Method já aplicado), uma mudança na regra de desconto ainda exigiria caçar e repetir a alteração em quatro classes diferentes.
- □ No limite em que um sistema tem uma única classe responsável por toda a lógica de negócio, sem nenhuma duplicação de regra em outro lugar, o risco de Cirurgia de Espingarda desaparece por definição, mesmo que o CBO dessa única classe seja extremamente alto.
- □ Num sistema de e-commerce onde a lógica de cálculo de frete está duplicada em
Pedido,NotaFiscaleRelatorioVendas, uma mudança na tabela de frete exigiria caçar e repetir a alteração nos três lugares — o mesmo Efeito Cascata/Cirurgia de Espingarda visto no exemplo de soma do carrinho. - □ Reduzir o CBO de uma classe para 1 (uma única dependência externa) já garante, por si só, que a lógica de negócio que ela usa não está duplicada em outras classes do sistema, prevenindo a Cirurgia de Espingarda.
- □ Coesão, CBO, Escala de Myers e GRASP são ferramentas complementares para diagnosticar e melhorar o design.
- □ Resolver Feature Envy automaticamente resolve também o acoplamento a classes concretas do Bloco de DIP.
- □ Um sistema bem desenhado combina baixo CBO, acoplamento de dados, especialistas corretos e abstrações estáveis.
- □ A jornada desta aula termina exatamente onde a próxima começa: como impor contratos de verdade no compilador.