Lei de Demeter: não fale com estranhos
1. O que é a Lei de Demeter?
A Lei de Demeter (LoD), também conhecida como "princípio do menor conhecimento", foi formulada no final dos anos 1980 no projeto Demeter da Northeastern University, liderado por Karl Lieberherr e Ian Holland. A ideia central é simples: um objeto deve conhecer e interagir apenas com seus vizinhos imediatos, evitando "conversar com estranhos".
Formalmente, a lei estabelece que um método M de um objeto O pode invocar métodos apenas de:
- O próprio objeto
O - Parâmetros recebidos por
M - Objetos criados diretamente dentro de
M - Objetos componentes diretos de
O(atributos)
A regra prática mais conhecida é a "regra dos pontos": em uma expressão como objeto.getX().getY().fazerAlgo(), cada ponto adicional representa uma violação potencial. Quanto mais pontos, maior a distância entre o objeto que chama e o objeto que executa a ação.
Exemplo clássico de violação:
// Violação da Lei de Demeter
public void imprimirEnderecoCliente(Cliente cliente) {
String cidade = cliente.getEndereco().getCidade();
System.out.println(cidade);
}
Aqui, a classe que chama imprimirEnderecoCliente está "falando" com Endereco, um objeto que não é seu vizinho direto — é um estranho.
2. Por que a Lei de Demeter é importante para a Arquitetura de Software?
A aplicação consistente da Lei de Demeter traz benefícios arquiteturais profundos:
Redução do acoplamento: Quando um objeto só se comunica com seus vizinhos imediatos, as dependências entre módulos diminuem drasticamente. Alterações em classes internas (como Endereco) não se propagam para consumidores distantes.
Aumento da coesão: Cada objeto assume a responsabilidade de mediar o acesso às suas partes internas. O objeto Cliente passa a oferecer métodos como obterCidadeDoEndereco(), mantendo o conhecimento encapsulado.
Manutenibilidade: Mudanças na estrutura interna de um objeto não exigem alterações em cascata. Se a classe Endereco mudar o nome do campo cidade para municipio, apenas o método delegado em Cliente precisa ser ajustado.
3. A relação com os princípios vizinhos
A Lei de Demeter não opera isolada. Ela se complementa com outros princípios de design:
DRY (Don't Repeat Yourself): Ao delegar responsabilidades, evitamos repetir lógica de navegação entre objetos em múltiplos lugares.
KISS (Keep It Simple, Stupid): Código que respeita a LoD tende a ser mais simples, com menos encadeamentos confusos.
Baixo acoplamento: A LoD é uma implementação prática desse conceito. Enquanto o baixo acoplamento é uma meta abstrata, a Lei de Demeter oferece uma regra concreta para alcançá-la.
Design Patterns: Padrões como Facade e Mediator nasceram da necessidade de gerenciar comunicações entre objetos, alinhando-se perfeitamente ao espírito da LoD.
4. Violações comuns e seus impactos
Encadeamento de métodos (train wreck):
// Train wreck - múltiplos pontos
pedido.getCliente().getConta().getSaldo().calcularJuros();
Isso cria uma dependência frágil: qualquer mudança na cadeia quebra o código.
Vazamento de implementação:
// Expondo objeto interno
public class Carro {
private Motor motor;
public Motor getMotor() { // Violação: expõe implementação
return motor;
}
}
Ao expor o motor diretamente, qualquer classe pode manipular seus detalhes internos, criando acoplamento desnecessário.
Dependências ocultas:
public void processar(Pedido pedido) {
// Dependência oculta: sabe que pedido tem cliente com endereço
pedido.getCliente().getEndereco().validar();
}
Se a classe Endereco mudar seu método validar() para validarEndereco(), o código quebra em um ponto distante.
5. Como aplicar a Lei de Demeter na prática
Antes (violação):
public class RelatorioVendas {
public void gerarRelatorio(Pedido pedido) {
String nomeCliente = pedido.getCliente().getNome();
String cidade = pedido.getCliente().getEndereco().getCidade();
double total = pedido.calcularTotal();
System.out.println("Cliente: " + nomeCliente);
System.out.println("Cidade: " + cidade);
System.out.println("Total: " + total);
}
}
Depois (correto):
public class RelatorioVendas {
public void gerarRelatorio(Pedido pedido) {
String nomeCliente = pedido.obterNomeCliente();
String cidade = pedido.obterCidadeCliente();
double total = pedido.calcularTotal();
System.out.println("Cliente: " + nomeCliente);
System.out.println("Cidade: " + cidade);
System.out.println("Total: " + total);
}
}
public class Pedido {
private Cliente cliente;
public String obterNomeCliente() {
return cliente.getNome();
}
public String obterCidadeCliente() {
return cliente.obterCidadeEndereco();
}
}
public class Cliente {
private Endereco endereco;
public String obterCidadeEndereco() {
return endereco.getCidade();
}
}
Note como cada objeto agora só fala com seus vizinhos imediatos. O princípio Tell, Don't Ask (Diga, não pergunte) é um aliado poderoso aqui: em vez de perguntar dados de objetos internos, diga a eles o que fazer.
6. Padrões de projeto que facilitam a Lei de Demeter
Facade: Fornece uma interface unificada para um subsistema complexo. O cliente interage apenas com a fachada, não com os objetos internos.
// Facade como aplicação da LoD
public class SistemaPedidosFacade {
private EstoqueService estoque;
private PagamentoService pagamento;
private EntregaService entrega;
public void processarPedido(Pedido pedido) {
estoque.reservarItens(pedido);
pagamento.cobrar(pedido);
entrega.agendar(pedido);
}
}
Mediator: Centraliza a comunicação entre objetos, evitando que eles se conheçam diretamente.
Adapter: Converte interfaces incompatíveis, permitindo que objetos "estranhos" sejam acessados através de um intermediário conhecido.
7. Limitações e críticas à Lei de Demeter
Apesar de seus benefícios, a Lei de Demeter não é absoluta. Existem contextos onde sua aplicação rígida pode ser contraproducente:
Performance: Em sistemas de alta performance, delegar cada chamada pode adicionar overhead desnecessário. Por exemplo, em loops críticos, um encadeamento direto pode ser aceitável.
Builders e fluent interfaces: Padrões como Builder dependem intencionalmente de encadeamento:
// Builder - violação aceitável
Pizza pizza = new PizzaBuilder()
.comMassa("fina")
.comQueijo("mussarela")
.comMolho("tomate")
.build();
Aqui, o encadeamento é o próprio padrão, e cada método retorna o próprio builder.
Streams funcionais: Em Java, encadeamentos como list.stream().filter(...).map(...).collect(...) são idiomáticos e não violam o espírito da LoD, pois cada etapa retorna um novo objeto de fluxo.
O equilíbrio está em entender quando a rigidez excessiva prejudica a legibilidade ou performance. A LoD é um guia, não uma lei imutável.
8. Conclusão e boas práticas
Para incorporar a Lei de Demeter no dia a dia, use este checklist ao revisar código:
- [ ] O método está acessando objetos que não são seus vizinhos diretos?
- [ ] Existem cadeias com mais de um ponto (
.) que poderiam ser delegadas? - [ ] Getters estão expondo objetos internos que poderiam ser encapsulados?
- [ ] Mudanças em classes internas exigiriam alterações em múltiplos consumidores?
Resumo: A Lei de Demeter é uma ferramenta poderosa para reduzir acoplamento e aumentar a manutenibilidade. Ela nos lembra que objetos devem ser educados: falar apenas com amigos próximos, não com estranhos.
Próximos passos: Comece refatorando as violações mais óbvias em seu código — aquelas cadeias de três ou mais pontos. Com o tempo, a aplicação da LoD se tornará natural, resultando em arquiteturas mais limpas e resilientes.
Referências
- Lei de Demeter — Wikipedia — Definição formal, histórico e exemplos do princípio desenvolvido no projeto Demeter.
- Law of Demeter: Don't Talk to Strangers — Martin Fowler — Artigo clássico de Martin Fowler explicando o princípio com exemplos práticos.
- The Law of Demeter: A Practical Guide — Refactoring Guru — Guia prático com exemplos de refatoração para respeitar a Lei de Demeter.
- Tell, Don't Ask — Martin Fowler — Princípio complementar que reforça o encapsulamento e evita violações da LoD.
- Lei de Demeter em Java: Exemplos e Boas Práticas — Baeldung — Tutorial detalhado com exemplos de código Java mostrando violações e correções.
- Design Patterns: Elements of Reusable Object-Oriented Software — Gang of Four — Livro clássico que apresenta padrões como Facade e Mediator, que facilitam a aplicação da LoD.