DEV Community

Determinado 96
Determinado 96

Posted on

Um resumo sobre o padrão de projeto Composite

Definição

O Composite é um padrão de projeto estrutural que permite compor objetos em estruturas de árvore e tratá-los de maneira uniforme, independentemente de serem objetos individuais ou composições.

Analogia

Imagine que você está em uma pasta que contém arquivos e outras pastas, você consegue abrir o arquivo e as outras pastas com a mesma operação. Isso é o composite. Ele permite tratar objetos individuais e composições de objetos da mesma forma, usando uma interface comum.

Estrutura mental simples

          Pasta (Composite)
         /        \
   Arquivo     Pasta (Composite)
                  |
               Arquivo
Enter fullscreen mode Exit fullscreen mode

Exemplo sem composite

class File {
  constructor(public name: string) { }

  open() {
    console.log(`Abrindo arquivo ${this.name}`);
  }
}

class Folder {
  constructor(
    public name: string,
    public items: any[],
  ) { }

  open() {
    console.log(`Abrindo pasta ${this.name}`);

    // Necessidade de verificar o tipo de cada item para abrir corretamente
    for (const item of this.items) {
      if (item instanceof File) {
        item.open();
      } else if (item instanceof Folder) {
        item.open();
      }
    }
  }
}

// uso
const file1 = new File('a.txt');
const file2 = new File('b.txt');

const folder = new Folder('docs', [file1, file2]);
folder.open();
Enter fullscreen mode Exit fullscreen mode

PS.: Note que é necessário ficar verificando a tipagem, isso causa acoplamente e dificulta mudanças.

Exemplo com composite

// Arquivo e pasta têm o mesmo contrato.
interface Component {
  open(): void;
}

class File implements Component {
  constructor(private name: string) { }

  open(): void {
    console.log(`Abrindo arquivo ${this.name}`);
  }
}

class Folder implements Component {
  private children: Component[] = [];

  constructor(private name: string) { }

  add(item: Component) {
    this.children.push(item);
  }

  open(): void {
    console.log(`Abrindo pasta ${this.name}`);

    for (const child of this.children) {
      child.open();
    }
  }
}

// Podemos aninhar infinitamente pastas e arquivos, e o cliente pode tratá-los da mesma forma.
const file1 = new File("a.txt");
const file2 = new File("b.txt");

const folder = new Folder("docs");
folder.add(file1);
folder.add(file2);

const root = new Folder("root");
root.add(folder);

root.open();
Enter fullscreen mode Exit fullscreen mode

PS.: Aqui utilizamos um contrato comum definido por uma interface. Isso permite que todos os elementos (objetos simples e compostos) sejam tratados de forma uniforme, dispensando a necessidade de checagem de tipos em tempo de execução.

Benefícios do Composite

  • Remove verificações de tipo (if/else, instanceof)
  • Facilita extensibilidade (OCP)
  • Permite estruturas recursivas naturalmente
  • Simplifica o código cliente
  • Representa hierarquias de forma elegante

Top comments (0)