Menu
Coddy logo textTech

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 parte-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. Seja lidando com um único arquivo ou com uma estrutura de pastas inteira, 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 contê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 as 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 UI 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 visualizar 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 tanto os funcionários quanto os departamentos implementarão. 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 inteiro.
  • Employee.java: Crie a classe folha que representa trabalhadores individuais. Um Employee tem um nome (String) e um salário (int), ambos definidos por meio do 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 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 em cada filho com o recuo aumentado (adicione dois espaços). O método getSalary retorna a soma dos salários de todos os filhos.
  • Main.java: Construa sua organização! Você receberá quatro entradas: dois nomes de funcionários com seus salários e o nome de um subdepartamento com um funcionário.

    Crie um departamento "Engineering" como sua 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 de employee1 (String), salário de employee1 (int), nome de employee2 (String), salário de employee2 (int), nome do subdepartamento (String), nome de employee3 (String), salário de 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 em um único funcionário ou em um departamento inteiro contendo subdepartamentos aninhados. A estrutura composta cuida da recursão automaticamente, permitindo tratar 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);
        
        // Ler 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: Create the "Engineering" department as the root
        
        // 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: Call showDetails("") on the Engineering department
        
        // 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