Pagar o passeador, não a mão dele
Para pagar quem passeou com seu cachorro, você não enfia a mão no bolso dele e tira o troco — você entrega o dinheiro e deixa que ele guarde. Meter a mão no bolso é passeador.getBolso().getCarteira().inserir(nota): você passou a depender de ele ter bolso, de ter carteira, de a carteira abrir. Entregar e deixar guardar é passeador.receber(valor). Deméter é exatamente isso: não mexa nos bolsos dos outros.
Quem são os amigos próximos
A regra lista com quem um método pode conversar: o próprio objeto (this), os objetos que ele recebeu como parâmetro, os que ele mesmo criou e seus campos diretos. Qualquer coisa além disso — navegar pelo que um método devolveu — é falar com um estranho.
O sintoma visível é a cadeia de pontos. Não porque pontos sejam proibidos, mas porque cada salto entre objetos diferentes é uma dependência nova na estrutura interna alheia.
Há uma exceção importante que evita o zelo cego: a lei fala de comportamento, não de dados burros. Encadear operações sobre uma mesma coleção (itens.filter(...).map(...)) ou navegar por um DTO/JSON de resposta não viola Deméter, porque não há comportamento nem invariante sendo violado — são estruturas de dados, não colaboradores. A lei protege o encapsulamento de objetos com regras, não a leitura de um saco de campos.
O corolário prático é 'tell, don't ask': pare de perguntar o estado de um objeto para decidir por ele e passe a mandar o objeto agir. if (conta.getSaldo() >= valor) conta.setSaldo(conta.getSaldo() - valor) vira conta.debitar(valor). A decisão migra para onde o dado vive, a cadeia de getters some, e a invariante (não ficar negativo) passa a ser guardada pelo dono do dado — não espalhada por quem o consome.
Como isso aparece na prática
A troca de endereço que quebrou o frete
Cenário
O cálculo de frete fazia pedido.getCliente().getEndereco().getCep(). O time de cadastro passou a permitir múltiplos endereços por cliente, mudando a estrutura — e o frete quebrou, longe de onde a mudança aconteceu.
Como o padrão entra
O pedido passou a expor calcularFrete(), guardando internamente qual endereço usar. Quem calcula frete deixou de conhecer a estrutura de cliente e endereço.
Trade-off: O pedido ganhou mais responsabilidade e um método a mais. Em troca, mudanças na estrutura de cliente pararam de vazar para o cálculo de frete.
O getter que virou método de negócio
Cenário
Vários lugares faziam conta.getSaldo() para checar e depois conta.setSaldo(...) para debitar. A regra 'saldo não fica negativo' estava espalhada e, num ponto, alguém esqueceu de checá-la.
Como o padrão entra
Os getters/setters de saldo foram substituídos por conta.debitar(valor), que carrega a invariante. A regra passou a morar num lugar só, dentro do dono do dado.
Trade-off: A conta ficou menos 'transparente' — não dá mais para mexer no saldo por fora. É exatamente o ponto: o encapsulamento voltou, e a invariante deixou de depender da disciplina de cada chamador.
- 1
Caçar o trem de getters
`a.getB().getC().getD()` atravessando objetos diferentes é o sintoma. Cada ponto a mais é acoplamento à estrutura alheia.
- 2
Perguntar quem decide
Se o chamador puxa dados para decidir, a decisão está no lugar errado. Migre a regra para o dono do dado.
- 3
Expor o que fazer, não o miolo
`pedido.calcularFrete()` ou `conta.debitar(valor)` — o objeto usa os próprios internos; quem chama fala só com o amigo próximo.
- 4
Evitar o mar de wrappers
Métodos-repasse (`getCidadeDoCliente`) escondem a cadeia sem remover o acoplamento. Se o meio ainda conhece toda a estrutura, Deméter não foi cumprida.
A Deméter que só escondeu os pontos
Compila, roda, passa no code review. E quebra depois.
A cadeia sumiu do chamador: agora é pedido.getCidadeDoCliente(). Parece limpo — mas o método-repasse ainda navega cliente → endereço → cidade. O acoplamento mudou de endereço, não sumiu.
// "Corrigiu" Demeter com metodos-repasse — a cadeia so mudou de lugar.
class Pedido {
getCidadeDoCliente() {
return this.cliente.getEndereco().getCidade(); // ainda conhece tudo
}
}
const cidade = pedido.getCidadeDoCliente();
// Quem chama nao ve pontos. Pedido ainda acopla a Cliente>Endereco>Cidade.O que quebra
- Ao mudar endereçoPedido quebra junto: ele ainda conhece a estrutura interna que o wrapper fingiu esconder.
- Na interfaceSurge um getter por campo distante (
getCepDoCliente,getUfDoCliente) — a fachada engorda sem encapsular de verdade. - No freteQuem calcula ainda depende da forma do cadastro; a regra não migrou para o dono do dado.
A saída: Tell, don't ask: pedido.calcularFrete() (ou equivalente) carrega a decisão. Não exponha a estrutura — peça ao objeto que faça o trabalho com ela.
Onde isto dá errado
Aplicar a lei a estruturas de dados puras
Navegar por um DTO ou um JSON de resposta não viola Deméter — não há comportamento a proteger. Criar métodos-repasse para cada campo de um saco de dados só engorda a interface sem ganho de encapsulamento.
Trocar a cadeia por um mar de wrappers
Cumprir a lei criando um método de repasse para cada acesso (getCidadeDoCliente, getCepDoCliente...) esconde a cadeia sem remover o acoplamento: o objeto do meio ainda conhece toda a estrutura, agora com mais código.
Confundir 'menos pontos' com 'melhor design'
O objetivo não é contar pontos, é reduzir o conhecimento que um objeto tem dos internos de outro. Uma linha com dois pontos que respeita 'tell, don't ask' é melhor que cinco métodos de repasse que fingem obedecer.
Do trem descarrilhado ao tell, don't ask
// VIOLACAO: o "trem descarrilhado" — cada ponto e um acoplamento.
const cidade = pedido.getCliente().getEndereco().getCidade();
// ^^^^ pedido conhece cliente, endereco E cidade.
// Mude a estrutura interna de qualquer um dos tres e esta linha quebra.
// Lei de Demeter: um metodo so pode falar com "amigos proximos":
// - o proprio objeto (this)
// - parametros que recebeu
// - objetos que ele mesmo criou
// - seus campos diretos
// ...nunca com o objeto que veio DE um retorno de outro.
// TELL, DON'T ASK: em vez de puxar os dados para decidir por fora,
// peca ao objeto que ele faça:
const frete = pedido.calcularFrete(); // pedido decide como, com seus internos
// Quem chama nao sabe (nem precisa saber) que existe cliente > endereco > cidade.Quando usar × quando evitar
Use quando
3- Ao ver cadeias de pontos atravessando objetos diferentes.
- Quando mudar a estrutura interna de uma classe quebra código distante.
- Ao escolher entre expor um getter ou oferecer um método que faz.
Evite quando
2- Em DTOs e respostas de API, onde navegar não acopla comportamento.
- Quando obedecer ao pé da letra só cria repasses sem valor.
Testar o que ficou
3 armadilhas de Lei de Deméter viram perguntas, com o nome do padrão escondido, misturadas com padrões parecidos.
Onde isto aparece de verdade
Você já usa isto, talvez sem saber o nome.
a.b.c.d encadeadoCada ponto a mais numa cadeia de acessos revela que um objeto conhece os internos de outro — a violação clássica de Deméter.o train wreck no códigopedido.getCliente().getEndereco().getCidade() é o 'trem descarrilhado' que Deméter proíbe: fale só com o vizinho direto.tell, don't askEm vez de puxar dados de dentro de um objeto para decidir por ele, peça a ele que faça — o corolário prático de Deméter.
O padrão em uma linha
Sem nome de domínio, sem cerimônia. Só a ideia.
// Fale só com amigos próximos — sem trem de getters.
pedido.cidadeEntrega(); // em vez de getCliente().getEndereco()...O que ele cobra
1 salto a mais entre a chamada e o efeito.
- Cumprir Deméter multiplica métodos de fachada que só repassam a chamada adiante
- Excesso de wrappers para 'não falar com estranhos' engorda a interface intermediária
Não vale se: a cadeia é sobre uma estrutura de dados burra e estável (um DTO, um JSON de resposta) — aí navegar por ela não acopla comportamento nenhum.
Onde isto aparece
Continue por aqui
- DIP — Inversão de DependênciaMódulos de alto nível não devem depender de módulos de baixo nível; ambos devem depender de abstrações — e a abstração pertence a quem a usa, não a quem a implementa.
- ISP — Segregação de InterfacesNenhum cliente deve ser forçado a depender de métodos que não usa: é melhor várias interfaces pequenas e específicas do que uma grande e genérica.
- FacadeOferece uma interface simples e de alto nível para um subsistema complexo, escondendo a coreografia entre as peças atrás de um único ponto de entrada.