Menu
CoddyTech

Padrão Composite

Parte da seção Programação Orientada a Objetos do Journey de Java da Coddy. Lição 75 de 87.

O padrão Composite é um padrão de projeto estrutural que permite compor objetos em estruturas de árvore para representar hierarquias de partes e todo. Ele permite que os clientes tratem objetos individuais e composições de objetos de maneira uniforme por meio de uma interface comum.

Pense em um sistema de arquivos: uma pasta pode conter arquivos e outras pastas, que podem conter mais arquivos e pastas. Quer você esteja lidando com um único arquivo ou com uma estrutura inteira de pastas, você quer realizar operações como "obter tamanho" da mesma maneira. O padrão define uma interface Component, objetos Leaf (elementos individuais) e objetos Composite (contêineres que têm elementos filhos):

interface FileComponent {
    void display(String indent);
    int getSize();
}

class File implements FileComponent {
    private String name;
    private int size;
    
    public File(String name, int size) {
        this.name = name;
        this.size = size;
    }
    
    public void display(String indent) {
        System.out.println(indent + name + " (" + size + "KB)");
    }
    
    public int getSize() {
        return size;
    }
}

class Folder implements FileComponent {
    private String name;
    private List<FileComponent> children = new ArrayList<>();
    
    public Folder(String name) {
        this.name = name;
    }
    
    public void add(FileComponent component) {
        children.add(component);
    }
    
    public void display(String indent) {
        System.out.println(indent + name + "/");
        for (FileComponent child : children) {
            child.display(indent + "  ");
        }
    }
    
    public int getSize() {
        return children.stream().mapToInt(FileComponent::getSize).sum();
    }
}

O composto delega operações aos seus filhos, permitindo estruturas recursivas. Os clientes interagem com a árvore sem saber se estão trabalhando com uma folha ou um composto:

Folder root = new Folder("Documents");
root.add(new File("resume.pdf", 150));

Folder photos = new Folder("Photos");
photos.add(new File("vacation.jpg", 2000));
root.add(photos);

root.display("");
System.out.println("Total: " + root.getSize() + "KB");

O padrão Composite é ideal para representar hierarquias como organogramas, componentes de interface do usuário ou sistemas de menu, nos quais você precisa tratar grupos e indivíduos de forma idêntica.

challenge icon

Desafio

Fácil

Vamos criar um sistema de organograma usando o Padrão Composite! Você criará uma estrutura na qual os departamentos podem conter funcionários e outros subdepartamentos, permitindo calcular os salários totais e exibir a hierarquia de maneira uniforme, seja ao analisar um único funcionário ou uma divisão inteira.

Você organizará seu código em quatro arquivos:

  • OrganizationComponent.java: Defina a interface do componente que será implementada tanto pelos funcionários quanto pelos departamentos. Ela deve declarar dois métodos: showDetails(String indent) para exibir o componente com o recuo adequado e getSalary(), que retorna o salário total como um número inteiro.
  • Employee.java: Crie a classe folha que representa funcionários individuais. Um Employee tem um nome (String) e um salário (int), ambos definidos pelo construtor. Quando showDetails é chamado, ele deve imprimir [indent][name]: $[salary]. O método getSalary simplesmente retorna o salário do funcionário.
  • Department.java: Crie a classe composta, que pode conter tanto funcionários quanto subdepartamentos. Um Department tem um nome (String) e mantém uma lista de filhos do tipo OrganizationComponent. Ele deve ter um método add(OrganizationComponent component) para adicionar membros. Quando showDetails é chamado, ele imprime [indent][name] Department e, em seguida, chama showDetails para cada filho com um recuo maior (adicione dois espaços). O método getSalary retorna a soma dos salários de todos os filhos.
  • Main.java: Monte sua organização! Você receberá quatro entradas: os nomes e salários de dois funcionários, e o nome de um subdepartamento com um funcionário.

    Crie um departamento "Engineering" como raiz. Adicione dois funcionários a ele usando os dois primeiros pares de nome/salário. Em seguida, crie um subdepartamento usando a terceira entrada, adicione um funcionário a ele usando o quarto par de nome/salário e adicione esse subdepartamento a Engineering.

    Chame showDetails("") no departamento Engineering e, em seguida, imprima o salário total no formato Total Salary: $[amount].

Você receberá as entradas nesta ordem: nome do employee1 (String), salário do employee1 (int), nome do employee2 (String), salário do employee2 (int), nome do subdepartamento (String), nome do employee3 (String), salário do employee3 (int).

Por exemplo, com as entradas Alice, 75000, Bob, 65000, QA, Charlie, 55000, sua saída seria:

Engineering Department
  Alice: $75000
  Bob: $65000
  QA Department
    Charlie: $55000
Total Salary: $195000

Observe como os mesmos métodos showDetails e getSalary funcionam perfeitamente, sejam chamados para um único funcionário ou para um departamento inteiro que contém subdepartamentos aninhados. A estrutura composta trata a recursão automaticamente, permitindo que você trabalhe com toda a hierarquia de maneira uniforme!

Experimente você mesmo

import java.util.Scanner;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        // Leia as entradas
        String emp1Name = scanner.nextLine();
        int emp1Salary = Integer.parseInt(scanner.nextLine());
        String emp2Name = scanner.nextLine();
        int emp2Salary = Integer.parseInt(scanner.nextLine());
        String subDeptName = scanner.nextLine();
        String emp3Name = scanner.nextLine();
        int emp3Salary = Integer.parseInt(scanner.nextLine());
        
        // TODO: Crie o departamento "Engineering" como raiz
        
        // TODO: Crie e adicione dois funcionários a Engineering usando os dados de emp1 e emp2
        
        // TODO: Crie um subdepartamento usando subDeptName
        
        // TODO: Crie e adicione um funcionário ao subdepartamento usando os dados de emp3
        
        // TODO: Adicione o subdepartamento a Engineering
        
        // TODO: Chame showDetails("") no departamento Engineering
        
        // TODO: Imprima o salário total no formato: Total Salary: $[amount]
    }
}
quiz iconTeste seus conhecimentos

Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.

Todas as lições de Programação Orientada a Objetos

Pratique por conta própria: Compilador de Java online