Pular para o conteúdo
GoF Padrões de Projeto Estruturais
Estrutural escopo de objeto
GoF, p. 163 também chamado de Object Tree

Composto

Composite

Trate objetos individuais e grupos de objetos exatamente da mesma forma.

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

Compor objetos em estruturas de árvore para representar hierarquias todo-parte. Composite permite que os clientes tratem objetos individuais e composições de objetos uniformemente.

Analogiauma imagem do mundo real

Caixas dentro de caixas

Um pedido chega em uma caixa grande. Dentro há caixas menores e produtos soltos; dentro das menores, mais caixas e mais produtos. Para calcular o preço total você não precisa de duas regras: pergunta o preço à caixa de fora, e ela pergunta a cada item dentro dela — produto responde seu próprio preço, caixa repete o processo recursivamente.

O problema

Você tem uma estrutura em árvore e precisa executar uma operação sobre ela toda. Sem o padrão, o cliente vive checando `if (é folha) … else percorre filhos …`, e essa verificação se espalha por todo lugar.

A solução

Declare uma interface comum a folhas e a nós compostos. O nó composto implementa a operação delegando aos filhos e agregando os resultados. O cliente chama o método na raiz e a recursão faz o resto.

Sintomascomo reconhecer no seu código
  • if (item instanceof Grupo) { ...percorre... } else { ...usa... } repetido.
  • Duas funções quase iguais, uma para item e outra para grupo.

Estrutura

usa0..* filhos ↺Client«interface»Componente+ operacao()Folha+ operacao()Composto- filhos[]+ add(c)+ operacao()
Fig. 8 — Composite herda / implementa cria usa / contém
Ver este diagrama sendo desenhado, traço a traço
Participantes
Component
Interface comum a folhas e composites.
Leaf
Elemento simples, sem filhos; faz o trabalho de verdade.
Composite
Contém filhos Component e delega o trabalho a eles.
Client
Trabalha com todos os elementos apenas via Component.

Implementação

Listagem 8 Sistema de arquivos: arquivos e pastas com a mesma interface
// ── Component: o contrato único ───────────────────────
class NoDoSistema {
  constructor(nome) { this.nome = nome; }
  get tamanho()          { throw new Error('abstrato'); }
  imprimir(nivel = 0)    { throw new Error('abstrato'); }
}

// ── Leaf: faz o trabalho de verdade ───────────────────
class Arquivo extends NoDoSistema {
  constructor(nome, bytes) { super(nome); this.bytes = bytes; }
  get tamanho() { return this.bytes; }
  imprimir(n = 0) { return `${'  '.repeat(n)}📄 ${this.nome} (${this.bytes} B)`; }
}

// ── Composite: delega aos filhos e agrega ─────────────
class Pasta extends NoDoSistema {
  constructor(nome, filhos = []) { super(nome); this.filhos = filhos; }
  add(no) { this.filhos.push(no); return this; }

  // A MESMA operação, resolvida recursivamente. Sem `if (é pasta)`.
  get tamanho() { return this.filhos.reduce((soma, f) => soma + f.tamanho, 0); }

  imprimir(n = 0) {
    return [`${'  '.repeat(n)}📁 ${this.nome}/ (${this.tamanho} B)`,
            ...this.filhos.map(f => f.imprimir(n + 1))].join('\n');
  }
}

const projeto = new Pasta('projeto')
  .add(new Arquivo('README.md', 1200))
  .add(new Pasta('src')
    .add(new Arquivo('index.js', 4800))
    .add(new Pasta('utils').add(new Arquivo('data.js', 900))));

console.log(projeto.imprimir());
console.log('total:', projeto.tamanho, 'bytes');   // 6900 — recursão transparente
Na práticaonde ele já existe
  • O DOM do navegador — Node, Element, TextNode
  • java.awt.Container / javax.swing.JComponent
  • Árvore de componentes React: um componente pode ser folha ou conter outros

Consequências

A favor
  • Trabalha com árvores complexas de forma simples, via polimorfismo e recursão.
  • Adiciona novos tipos de elemento sem quebrar o código existente (Aberto/Fechado).
  • O cliente fica trivialmente simples: uma chamada na raiz.
Contra
  • Pode ser difícil dar uma interface comum a classes muito diferentes — o risco é uma interface genérica demais.
  • Métodos como `add`/`remove` na interface comum não fazem sentido para folhas (dilema segurança × transparência).
Use quando
  • Seu modelo de dados tem forma de árvore (menus, organogramas, DOM, categorias).
  • Você quer que o cliente ignore a diferença entre item e grupo.
Evite quando
  • A estrutura não é hierárquica — forçar Composite aqui só complica.

Relações com outros padrões

costuma andar junto
Builder
Builder monta árvores Composite passo a passo.
Iterator
Iterator percorre a árvore sem expor sua estrutura interna.
Visitor
Visitor executa operações sobre a árvore inteira sem inchar as classes dos nós.
Chain of Responsibility
O elo seguinte da cadeia pode ser o nó pai na árvore.
Flyweight
Folhas repetidas podem ser compartilhadas como flyweights.
parecido / fácil de confundir
Decorator
Ambos são estruturas recursivas; Decorator tem exatamente UM filho e adiciona responsabilidade.

Verificação

Questãoa resposta está marcada

O benefício central do Composite para o código CLIENTE é:

  1. Poder tratar um objeto único e um grupo inteiro com a mesma chamada, sem verificar o tipo
  2. Reduzir o consumo de memória em árvores grandes
  3. Permitir adicionar comportamento em tempo de execução
  4. Garantir que a árvore nunca tenha mais de um nível

A uniformidade é o ponto. Reduzir memória por compartilhamento é Flyweight; adicionar comportamento dinamicamente é Decorator.