Exercícios — Decomposição e Responsabilidade
Aula 4 — Programação Orientada a Objetos
Marcos M. Raimundo — Instituto de Computação, UNICAMP
Questões discursivas
A classe
Pedidodo início desta aula tinha cinco responsabilidades (cálculo, imposto, formatação, persistência, e-mail). Escolha duas delas e explique, para cada uma, qual “ator” (departamento ou stakeholder) provavelmente solicitaria mudanças nela — e por que isso já é evidência de violação do SRP.Um colega decide aplicar o SRP “ao pé da letra” e separa a classe
Pedidoem 12 classes de uma linha cada, uma para cada campo. Explique, usando os conceitos de Cirurgia de Espingarda e Modelo Anêmico, por que essa fragmentação pode ser pior do que a Classe Deus original.Explique a diferença entre Agregação e Composição usando o exemplo de
ClienteeCartao. Por que essa escolha de design depende de uma decisão sobre o domínio de negócio (o que acontece com o cartão quando a conta é excluída), e não apenas de como o atributo é declarado em código?
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).
- □ É identificada por centralizar lógicas de múltiplos atores (financeiro, infraestrutura, UI) num único arquivo.
- □ O “Teste do E” ajuda a diagnosticá-la: se a classe faz X E Y, provavelmente tem responsabilidades demais.
- □ Uma Classe Deus facilita a manutenção, pois toda a lógica fica concentrada num só lugar.
- □ Testar isoladamente uma responsabilidade de uma Classe Deus costuma exigir efeitos colaterais indesejados (e-mail, banco).
- □ Se duas classes com métodos completamente distintos (sem nenhum atributo em comum) fossem fundidas numa única classe apenas para reduzir o número de arquivos do projeto, essa fusão aumentaria a coesão do sistema.
- □ No limite em que uma classe
Adepende de tantos detalhes internos de uma classeBque qualquer mudança emBobriga a reescreverA, dizemos queAeBtêm acoplamento muito baixo. - □ Numa oficina mecânica organizada em bancadas por especialidade (uma para motor, uma para elétrica, uma para funilaria), cada bancada guardando só as ferramentas da sua especialidade é uma analogia de alta coesão, assim como a caixa de ferramentas só com chaves de fenda desta aula.
- □ Duas classes podem ter baixo acoplamento entre si mesmo que cada uma, isoladamente, tenha baixíssima coesão.
- □ Se uma classe tiver apenas um único método público, isso já garante que ela respeita o SRP.
- □ Se a descrição de uma classe exige a conjunção “E”, ela provavelmente viola o SRP.
- □ Aplicar o SRP significa que uma classe só pode ter um único método público.
- □
Pedidoque calcula total, processa pagamento e envia e-mail no mesmo método viola o SRP.
- □ Se
Pedidocontinuasse criandonew CartaoDeCredito()enew ServicoEmail()dentro do próprio construtor, mas guardasse essas instâncias em atributos privados corretamente encapsulados, isso já seria suficiente para obter os ganhos de testabilidade da Injeção de Dependência. - □ A injeção via construtor garante que o objeto nunca exista sem suas dependências essenciais.
- □ A DI aumenta o acoplamento, pois obriga o objeto a conhecer quem o instanciou.
- □ Sem DI, testar
Pedido.finalizar()isoladamente, sem efeitos colaterais reais, é muito mais difícil.
- □ Numa fintech em que o mesmo microsserviço calcula o score de crédito (usado pelo time de Risco) e também formata esse score para exibição no app do cliente (usado pelo time de Produto), esse serviço, pela Teoria do Ator, tem apenas uma razão para mudar, pois lida com um único conceito: “score de crédito”.
- □ Misturar lógica solicitada pelo RH e pelo Financeiro na mesma classe é seguro, pois são setores diferentes.
- □ O conflito de atores é uma fonte comum de “quebras colaterais” em classes com múltiplas razões de mudança.
- □ No limite em que uma empresa tem um único departamento responsável por todas as decisões de negócio (sem separação entre financeiro, RH, produto etc.), a Teoria do Ator deixaria de fazer qualquer distinção útil entre classes, pois haveria apenas um ator possível para todo o sistema.
- □ No limite em que todo método de uma classe usa exatamente os mesmos atributos que todos os outros métodos, o LCOM dessa classe seria o mais alto possível.
- □ Um LCOM alto indica uma classe muito coesa e bem projetada.
- □ Se metade dos métodos usa o atributo A e a outra metade usa só o atributo B, a classe deveria ser dividida.
- □ LCOM é uma forma de provar matematicamente que uma classe é, na prática, duas classes disfarçadas.
- □ Num sistema de e-commerce em que adicionar um novo campo obrigatório (“CPF do comprador”) ao formulário de checkout exige editar 20 classes de uma linha cada (uma para nome, uma para e-mail, uma para CPF etc.), esse cenário ilustra a Cirurgia de Espingarda, e a solução recomendada pela aula é sempre criar ainda mais classes minúsculas para isolar o novo campo.
- □ O Modelo Anêmico é uma consequência possível da aplicação fanática e sem pragmatismo do SRP.
- □ O SRP proíbe que uma classe como
Contagerencie seu próprio saldo internamente. - □ Como o SRP recomenda alta coesão, uma classe
Contaque gerencia tantodebitar()quantocreditar()sobre o mesmo saldo já é, por si só, uma violação leve do SRP, pois tem dois métodos que alteram o mesmo estado.
- □ Se um método recebesse um objeto como parâmetro e o armazenasse permanentemente num atributo da classe logo na primeira linha do método, essa relação continuaria sendo classificada como Dependência.
- □ O objeto usado numa dependência costuma ser guardado como atributo de longo prazo.
- □ Um método de uma API de pagamentos que recebe um objeto
ContextoDeAuditoriasó para registrar um log da chamada atual, sem guardar essa referência para uso posterior, exemplifica o mesmo tipo de vínculo fraco (Dependência) visto emCarrinho.confereTotal(). - □
Carrinho.confereTotal(ArrayList<Produto> itens)recebendo a lista como parâmetro é um exemplo de dependência.
- □ Se, no exemplo do
Carrinhoe dosProduto, destruir o carrinho (carrinho = null) também apagasse osProdutodo catálogo do sistema, essa relação ainda seria corretamente chamada de Agregação. - □ Se um
Carrinhofor destruído, osProdutoque ele referenciava também são destruídos. - □ Vários objetos “todo” diferentes podem referenciar o mesmo objeto “parte” simultaneamente.
- □ É uma forma de posse mais fraca do que a Composição.
- □ No limite em que um objeto “parte” de uma Composição pudesse ser compartilhado por dois objetos “todo” diferentes ao mesmo tempo, a relação continuaria sendo, por definição, uma Composição.
- □ Num sistema de RH em que cada
Funcionariotem seu próprioHistoricoDisciplinar, criado apenas quando o funcionário é contratado e apagado quando o funcionário é desligado do sistema, essa relação seria mais bem classificada como Composição do que como Agregação. - □ Um
Documentoe suasPaginasão um exemplo clássico de Composição. - □ A escolha entre Agregação e Composição é sempre puramente sintática, nunca uma decisão de negócio.
- □ Se um método
pagar()delegasse aoCartaoa operação de processar o valor, mas antes disso navegasse porthis.cartao.getBanco().getGerente()só para registrar um log, essa navegação extra ainda seria uma delegação limpa, sem qualquer violação de Demeter. - □
joao.getCartao().processar(500.0)é um exemplo correto de delegação. - □
joao.pagar(500.0), delegando internamente aoCartao, corrige a violação de Demeter do exemplo anterior. - □ A delegação é o mecanismo que torna a composição uma alternativa flexível à herança.
- □ Num sistema de estoque em que, antes de vender um produto, o código lê
produto.getQuantidade()eproduto.getQuantidadeMinima()para decidir por fora se a venda é permitida, esse padrão está alinhado com “Tell, Don’t Ask”, da mesma forma quepedido.clientePodePagar()está. - □ Associação, SRP e Delegação são princípios independentes, sem nenhuma relação entre si.
- □ Um sistema bem decomposto reduz a carga cognitiva ao permitir raciocinar sobre uma responsabilidade por vez.
- □ Delegar ao especialista certo permite trocar sua implementação sem que o orquestrador precise mudar.