Pular para o conteúdo
GoF Padrões de Projeto Comportamentais
Comportamental escopo de objeto
GoF, p. 223 também chamado de CoR, Chain of Command

Cadeia de Responsabilidade

Chain of Responsibility

Passe o pedido por uma fila de handlers até que um deles resolva.

Complexidade média Frequência de uso moderada
Intençãocomo o livro define

Evitar o acoplamento entre o remetente de uma solicitação e seu receptor, dando a mais de um objeto a chance de tratar a solicitação. Encadear os objetos receptores e passar a solicitação ao longo da cadeia até que um a trate.

Analogiauma imagem do mundo real

O suporte técnico em níveis

Você liga para o suporte. O robô tenta resolver; não conseguiu, passa para o atendente nível 1; não conseguiu, nível 2; não conseguiu, engenharia. Cada nível conhece apenas o próximo. Você, do outro lado da linha, não faz ideia de quantos níveis existem — só fez um pedido.

O problema

Um pedido precisa passar por várias verificações sequenciais (autenticação, limite de taxa, cache, validação, sanitização). Empilhar tudo numa função gera um bloco monstruoso de `if`s aninhados, impossível de reordenar ou reaproveitar em outra rota.

A solução

Transforme cada verificação em um objeto handler com um único método `tratar()`. Cada handler guarda uma referência ao próximo e decide: trata e para, trata e passa adiante, ou passa adiante direto. A cadeia é montada dinamicamente pelo cliente.

Sintomascomo reconhecer no seu código
  • Uma função com dez if (…) return erro; em sequência.
  • A mesma sequência de validações copiada entre controllers.

Estrutura

tratar(req)próximo ↺Client«interface»Handler+ setProximo(h)+ tratar(req)AutenticacaoLimiteDeTaxaValidacao
Fig. 13 — Chain of Responsibility herda / implementa cria usa / contém
Ver este diagrama sendo desenhado, traço a traço
Participantes
Handler
Interface comum; normalmente guarda o próximo elo.
BaseHandler
(opcional) Implementa o encadeamento e o repasse padrão.
ConcreteHandler
Trata o que sabe tratar; decide se interrompe ou continua.
Client
Monta a cadeia e dispara o pedido no primeiro elo.

Implementação

Listagem 13 Pipeline de validação de uma requisição HTTP
class Handler {
  #proximo = null;
  // Encadeamento fluente: a.encadear(b).encadear(c) devolve a ponta.
  encadear(proximo) { this.#proximo = proximo; return proximo; }

  tratar(req) {
    // Comportamento padrão: repassar. Se não há próximo, ninguém barrou → OK.
    return this.#proximo ? this.#proximo.tratar(req) : { ok: true, req };
  }
}

class Autenticacao extends Handler {
  tratar(req) {
    if (!req.token) return { ok: false, erro: '401 sem token' };   // ⛔ interrompe
    req.usuario = { id: 7, papel: 'editor' };
    return super.tratar(req);                                      // ✅ segue
  }
}

class Autorizacao extends Handler {
  constructor(papel) { super(); this.papel = papel; }
  tratar(req) {
    if (req.usuario.papel !== this.papel) return { ok: false, erro: '403 sem permissão' };
    return super.tratar(req);
  }
}

class LimiteDeTaxa extends Handler {
  #contagem = new Map();
  tratar(req) {
    const n = (this.#contagem.get(req.ip) ?? 0) + 1;
    this.#contagem.set(req.ip, n);
    if (n > 3) return { ok: false, erro: '429 muitas requisições' };
    return super.tratar(req);
  }
}

class Sanitizacao extends Handler {
  tratar(req) {
    req.corpo = String(req.corpo ?? '').replace(/<[^>]*>/g, '');    // trata e SEGUE
    return super.tratar(req);
  }
}

// ── O cliente monta a cadeia — a ORDEM é uma decisão dele ──
const inicio = new LimiteDeTaxa();
inicio.encadear(new Autenticacao())
      .encadear(new Autorizacao('editor'))
      .encadear(new Sanitizacao());

console.log(inicio.tratar({ ip: '1.1.1.1', token: 'abc', corpo: '<script>x</script>Oi' }));
// { ok: true, req: { …, corpo: 'Oi' } }
console.log(inicio.tratar({ ip: '1.1.1.1' }));   // { ok: false, erro: '401 sem token' }
Na práticaonde ele já existe
  • javax.servlet.Filter / FilterChain
  • Middlewares de Express, Koa, ASP.NET Core
  • Propagação de eventos no DOM (bubbling)
  • java.util.logging.Logger — handlers em cadeia

Consequências

A favor
  • Controla a ordem de tratamento a partir do cliente.
  • Cada handler faz uma coisa só (Responsabilidade Única).
  • Novos handlers entram sem alterar os existentes (Aberto/Fechado).
  • Desacopla quem pede de quem trata.
Contra
  • Um pedido pode chegar ao fim sem ser tratado por ninguém.
  • Depuração fica mais difícil: o fluxo é dinâmico e não aparece no código.
Use quando
  • Vários objetos podem tratar um pedido e o handler certo só é conhecido em tempo de execução.
  • A ordem de execução dos tratamentos precisa ser configurável.
  • O conjunto de handlers muda dinamicamente.
Evite quando
  • Sempre existe exatamente um tratador conhecido — uma chamada direta é mais clara.

Relações com outros padrões

costuma andar junto
Command
Handlers podem ser implementados como Commands executados sobre um contexto.
Composite
A cadeia pode seguir os pais de uma árvore Composite.
parecido / fácil de confundir
Decorator
Estruturas muito parecidas; na Chain qualquer elo pode ABORTAR o fluxo, no Decorator todos executam.
alternativa a
Mediator
Outra forma de desacoplar remetente e receptor, mas centralizada.

Verificação

Questãoa resposta está marcada

Qual a diferença prática entre Chain of Responsibility e Decorator?

  1. Na Chain, um elo pode interromper e não repassar; no Decorator todas as camadas participam da chamada
  2. A Chain só funciona com no máximo três elos
  3. O Decorator não pode alterar os argumentos
  4. A Chain exige herança e o Decorator, composição

Ambos formam uma pilha de objetos que se delegam. A intenção difere: a Chain busca QUEM trata (e para ali); o Decorator ENRIQUECE, e todos contribuem.