O padrão Composite é um padrão de design estrutural que tem como objetivo principal compor objetos em estruturas de árvore para representar hierarquias parte-todo. Este padrão permite que clientes tratem objetos individuais e composições de objetos de maneira uniforme. O problema que o Composite visa resolver inclui:
-
Manipulação Uniforme de Objetos Individuais e Compostos: Em muitos sistemas, é útil tratar objetos individuais e suas composições de forma uniforme. Por exemplo, você pode querer tratar um único gráfico e um grupo de gráficos da mesma maneira.
-
Simplificação de Estruturas Complexas: O Composite simplifica o trabalho com estruturas complexas, permitindo que os clientes interajam com todos os elementos da estrutura de forma consistente, seja um elemento simples ou um composto.
-
Flexibilidade na Criação de Estruturas: Permite a construção de estruturas complexas dinamicamente, adicionando ou removendo novos elementos, seja um único objeto ou um grupo de objetos.
-
Promoção de Reutilização: Ao tratar objetos individuais e composições da mesma maneira, o Composite pode ajudar a promover a reutilização do código, pois o mesmo código pode trabalhar com objetos simples ou complexos.
Como Funciona
O padrão Composite geralmente envolve três tipos de objetos:
- Componente: Uma interface ou classe abstrata que define operações comuns para objetos simples e compostos.
- Folha (Leaf): Representa objetos individuais na composição. Eles implementam operações da interface Componente, mas normalmente não têm filhos.
- Composto (Composite): Uma classe que armazena filhos (que podem ser outros compostos ou folhas) e implementa operações da interface Componente. As operações implementadas pelos compostos geralmente delegam trabalho a seus filhos.
Exemplo
Um exemplo clássico do uso do padrão Composite é em sistemas de arquivos, onde tanto arquivos individuais quanto diretórios podem ser tratados de maneira uniforme. Um diretório (Composite) pode conter arquivos (Leaf) e outros diretórios. Ao invocar uma operação como “exibir informações”, esta operação pode ser aplicada a um arquivo individual ou a um diretório inteiro, tratando ambos de maneira uniforme.
Exemplo de implementação
Vamos considerar um exemplo usando uma estrutura organizacional de uma empresa como exemplo. Neste caso, podemos tratar tanto funcionários individuais quanto departamentos (que consistem em grupos de funcionários) de maneira uniforme.
Definindo a Interface Componente
public interface Organizacao {
void exibirDetalhes();
}Implementando a Folha (Leaf)
public class Funcionario implements Organizacao {
private String nome;
private String cargo;
public Funcionario(String nome, String cargo) {
this.nome = nome;
this.cargo = cargo;
}
@Override
public void exibirDetalhes() {
System.out.println(nome + " - " + cargo);
}
}Implementando o Composto (Composite)
import java.util.ArrayList;
import java.util.List;
public class Departamento implements Organizacao {
private List<Organizacao> membros;
private String nomeDepartamento;
public Departamento(String nomeDepartamento) {
this.nomeDepartamento = nomeDepartamento;
membros = new ArrayList<>();
}
public void adicionarMembro(Organizacao membro) {
membros.add(membro);
}
@Override
public void exibirDetalhes() {
System.out.println("Departamento: " + nomeDepartamento);
for (Organizacao membro : membros) {
membro.exibirDetalhes();
}
}
}Utilizando o Padrão Composite
public class Main {
public static void main(String[] args) {
Funcionario funcionario1 = new Funcionario("João", "Desenvolvedor");
Funcionario funcionario2 = new Funcionario("Maria", "Designer");
Departamento departamentoDesenvolvimento = new Departamento("Desenvolvimento");
departamentoDesenvolvimento.adicionarMembro(funcionario1);
Departamento departamentoDesign = new Departamento("Design");
departamentoDesign.adicionarMembro(funcionario2);
Departamento sede = new Departamento("Sede");
sede.adicionarMembro(departamentoDesenvolvimento);
sede.adicionarMembro(departamentoDesign);
sede.exibirDetalhes();
}
}Neste exemplo, ==Funcionario representa a folha, enquanto Departamento representa o composite==. Cada departamento pode conter vários membros, que podem ser outros departamentos ou funcionários. Ao chamar exibirDetalhes() em um departamento, ele exibe os detalhes de todos os seus membros. Isso demonstra como o padrão Composite pode ser usado para gerenciar e organizar estruturas hierárquicas complexas, como uma estrutura organizacional de uma empresa.