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
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();
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();
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)