PrincípioIniciante5 min de leitura6 seções1987, Data aproximada

Lei de Deméter

Fale apenas com os amigos próximos. Um método deve interagir só com o próprio objeto, seus campos, seus parâmetros e o que ele mesmo cria — nunca navegar por dentro do que um objeto devolveu. Cada ponto a mais numa cadeia (a.getB().getC().getD()) é um acoplamento à estrutura interna de outro, que quebra quando essa estrutura muda.

Em 10 segundos

A Lei de Deméter diz: fale só com os amigos próximos — o próprio objeto, seus campos, parâmetros e o que ele criou —, nunca com o que veio do retorno de outro. Cada ponto a mais numa cadeia como a.getB().getC() acopla você à estrutura interna alheia. A saída é 'tell, don't ask': em vez de puxar os dados para decidir por fora, peça ao objeto que ele faça, e a cadeia desaparece.

Antes de ter nome

O nome vem do projeto Demeter; a ideia de 'falar só com vizinhos próximos' generaliza o baixo acoplamento que o design estruturado já perseguia.

  • #principio
  • #acoplamento
  • #encapsulamento
  • #tell-dont-ask
Analogia

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.

01Conceito

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.

02No mundo real

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.

Passo a passoComo aplicar tell, don't ask
  1. 1

    Caçar o trem de getters

    `a.getB().getC().getD()` atravessando objetos diferentes é o sintoma. Cada ponto a mais é acoplamento à estrutura alheia.

  2. 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. 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. 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.

04Cuidado

Onde isto dá errado

  1. 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.

  2. 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.

  3. 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.

05Implementação

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.
06Decisão

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