Padrão Composite
Parte da seção Programação Orientada a Objetos do Journey de PHP da Coddy. Lição 80 de 91.
O Composite Pattern é um padrão de projeto estrutural que permite compor objetos em estruturas de árvore e, em seguida, trabalhar com essas estruturas como se fossem objetos individuais. Ele é perfeito para representar hierarquias parte-todo nas quais você deseja tratar objetos individuais e grupos de objetos de maneira uniforme.
Considere um sistema de arquivos. Uma pasta pode conter arquivos e outras pastas.
Ao calcular o tamanho total, você quer chamar o mesmo método tanto em arquivos quanto em pastas, e as pastas devem somar recursivamente seus conteúdos. O Padrão Composite torna isso simples ao fornecer a mesma interface tanto para as folhas (arquivos) quanto para os compostos (pastas).
<?php
interface FileSystemItem {
public function getName(): string;
public function getSize(): int;
}
class File implements FileSystemItem {
public function __construct(
private string $name,
private int $size
) {}
public function getName(): string {
return $this->name;
}
public function getSize(): int {
return $this->size;
}
}
class Folder implements FileSystemItem {
private array $items = [];
public function __construct(private string $name) {}
public function getName(): string {
return $this->name;
}
public function add(FileSystemItem $item): void {
$this->items[] = $item;
}
public function getSize(): int {
$total = 0;
foreach ($this->items as $item) {
$total += $item->getSize();
}
return $total;
}
}
Agora você pode criar estruturas de árvore e tratá-las de maneira uniforme:
<?php
$docs = new Folder("Documents");
$docs->add(new File("resume.pdf", 250));
$docs->add(new File("cover.docx", 50));
$images = new Folder("Images");
$images->add(new File("photo.jpg", 1500));
$root = new Folder("Root");
$root->add($docs);
$root->add($images);
$root->add(new File("readme.txt", 10));
echo $root->getSize();
Saída:
1810O código do cliente chama getSize() sem se importar se está lidando com um único arquivo ou com uma estrutura de pastas profundamente aninhada. O padrão trata da recursão internamente, tornando hierarquias complexas fáceis de manipular.
Desafio
FácilVamos criar um sistema de organograma usando o Padrão Composite. As empresas têm uma estrutura hierárquica na qual os departamentos podem conter funcionários e outros subdepartamentos: uma estrutura de árvore perfeita em que você deseja calcular os totais uniformemente em toda a organização.
Você organizará seu código em quatro arquivos:
OrganizationUnit.php: Defina uma interfaceOrganizationUnitque tanto os funcionários individuais quanto os departamentos implementarão. Ela deve ter dois métodos:getName(): stringegetSalary(): int. Essa interface comum permite tratar funcionários individuais e departamentos inteiros da mesma maneira ao calcular os custos.Employee.php: Inclua a interface OrganizationUnit e crie uma classeEmployeeque a implemente. Um funcionário é um nó folha na árvore da organização. Ele tem um nome e um salário, mas não pode conter outras unidades. Use a promoção de construtor para aceitar o nome e o salário e implemente os dois métodos da interface.Department.php: Inclua a interface OrganizationUnit e crie uma classeDepartmentque a implemente. Um departamento é um composto que pode conter tanto funcionários quanto outros departamentos. Seu departamento deve:- Aceitar um nome em seu construtor
- Implementar
getName()para retornar o nome do departamento - Ter um método
add(OrganizationUnit $unit): voidpara adicionar funcionários ou subdepartamentos - Implementar
getSalary()para retornar o salário total de todas as unidades que ele contém (somando recursivamente tudo o que estiver dentro)
main.php: Inclua os arquivos Employee e Department. Você receberá uma entrada: uma string JSON que representa a estrutura da organização.O JSON estará neste formato:
{"Engineering": [{"name": "Alice", "salary": 80000}, {"name": "Bob", "salary": 75000}], "Sales": [{"name": "Carol", "salary": 65000}]}Cada chave é o nome de um departamento, e seu valor é um array de funcionários com seus nomes e salários.
Crie um
Departmentraiz chamado"Company". Para cada departamento no JSON, crie umDepartment, adicione seus funcionários e, em seguida, adicione esse departamento à Company. Por fim, imprima o salário total da empresa neste formato:Total Salary: [amount]
A beleza do Padrão Composite é que chamar getSalary() no departamento Company calcula automaticamente a soma de todos os departamentos e funcionários aninhados: o código cliente não precisa conhecer a estrutura interna.
Experimente você mesmo
<?php
require_once 'Employee.php';
require_once 'Department.php';
// Leia a entrada JSON
$input = trim(fgets(STDIN));
$data = (array)json_decode($input, true);
// TODO: Crie um Department raiz chamado "Company"
// TODO: Percorra cada department nos dados JSON
// Para cada department:
// - Crie um novo objeto Department
// - Adicione cada employee a esse department
// - Adicione o department à Company
// TODO: Imprima o salário total no formato: Total Salary: [amount]
?>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
1Fundamentos de OOP
Arquivos externosIntrodução à OOPClasses vs. objetosA palavra-chave $thisMétodosPropriedadesConstrutor (__construct)Destrutor (__destruct)Recapitulação - Calculadora simples4Herança
Herança BásicaA Palavra-chave parent::Sobrescrita de MétodosA Palavra-chave finalClasses AbstratasRecapitulação - Hierarquia de Funcionários7Encapsulamento
Público, Protegido, PrivadoModificadores de Acesso em ProfundidadeGetters e SettersOcultação de InformaçõesPromoção de Construtor (8.0)Recapitulação - Sistema de Registros de Alunos10Conceitos Avançados de OOP
Composição vs. HerançaInjeção de DependênciaClasses AnônimasEnums (PHP 8.1)Fibras (PHP 8.1)Análise Profunda da Clonagem de ObjetosGeradores e Iteradores13Padrões de Projeto Parte 2
Padrão CommandPadrão AdapterPadrão DecoratorPadrão Template MethodPadrão StatePadrão CompositePadrão Repository2Namespaces e Autoloading
Introdução a NamespacesA palavra-chave usePadrão de Autoloading PSR-4Autoloader do ComposerRecapitulação - Projeto organizado5Interfaces e Contratos
Introdução às InterfacesImplementando InterfacesImplementação de Múltiplas InterfacesInterface vs Classe AbstrataTipagem com InterfacesRecapitulação - Calculadora de Formas8Métodos Mágicos
Introdução aos Métodos Mágicos__toString e __debugInfo__get, __set, __isset, __unset__call e __callStatic__clone e Clonagem de Objetos__serialize e __unserializeRecapitulação - Coleção Personalizada11Sistema de Tipos e Tratamento de Erros
Declarações de TiposTipos NulosTipos de União e InterseçãoClasses de ExceçãoHierarquia de Exceções PersonalizadaTry, Catch, FinallyRecapitulação - Validador de Formulário14Projeto: Gerenciamento de Biblioteca
Visão Geral do ProjetoClasses de Livros e Usuários3Propriedades de Classes
Propriedades de Instância vs. EstáticasConstantes em ClassesMétodos e Propriedades EstáticosPropriedades Privadas e ProtegidasPropriedades Somente para Leitura (PHP 8.1)Recapitulação - Gerenciador de Contas Bancárias6Polimorfismo
Revisão da Sobrescrita de MétodosPolimorfismo via InterfacesIndicação de Tipos e Tipos UnionVinculação Estática TardiaRecapitulação - Processador de Pagamentos9Traits
Introdução a TraitsUsando Múltiplos TraitsResolução de Conflitos entre TraitsMétodos Abstratos em TraitsTraits vs. Herança12Padrões de Projeto – Parte 1
Introdução aos Padrões de ProjetoPadrão SingletonPadrão FactoryPadrão ObserverPadrão StrategyPratique por conta própria: Compilador de PHP online