Modello Composite
Fa parte della sezione Programmazione orientata agli oggetti del percorso PHP di Coddy. Lezione 80 di 91.
Il Composite Pattern è un pattern strutturale che consente di comporre oggetti in strutture ad albero e di lavorare con queste strutture come se fossero oggetti singoli. È perfetto per rappresentare gerarchie parte-tutto in cui vuoi trattare in modo uniforme gli oggetti singoli e i gruppi di oggetti.
Considera un file system. Una cartella può contenere file e altre cartelle.
Quando calcoli la dimensione totale, vuoi chiamare lo stesso metodo sia sui file sia sulle cartelle, e le cartelle dovrebbero sommare ricorsivamente i propri contenuti. Il Composite Pattern rende tutto questo semplice, fornendo la stessa interfaccia sia alle foglie (file) sia ai compositi (cartelle).
<?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;
}
}
Ora puoi creare strutture ad albero e trattarle in modo 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();
Output:
1810Il codice client chiama getSize() senza preoccuparsi se ha a che fare con un singolo file o con una struttura di cartelle profondamente annidata. Il pattern gestisce la ricorsione internamente, rendendo facile lavorare con gerarchie complesse.
Sfida
FacileCreiamo un sistema di organigramma usando il Composite Pattern. Le aziende hanno una struttura gerarchica in cui i reparti possono contenere dipendenti e altri sottoreparti: una struttura ad albero perfetta per calcolare i totali in modo uniforme in tutta l’organizzazione.
Organizzerai il codice in quattro file:
OrganizationUnit.php: Definisci un’interfacciaOrganizationUnitche sarà implementata sia dai singoli dipendenti sia dai reparti. Dovrebbe avere due metodi:getName(): stringegetSalary(): int. Questa interfaccia comune ti permette di trattare allo stesso modo i singoli dipendenti e i reparti interi quando calcoli i costi.Employee.php: Includi l’interfaccia OrganizationUnit e crea una classeEmployeeche la implementa. Un dipendente è una foglia nell’albero dell’organizzazione. Ha un nome e uno stipendio, ma non può contenere altre unità. Usa la promozione delle proprietà del costruttore per accettare il nome e lo stipendio e implementa entrambi i metodi dell’interfaccia.Department.php: Includi l’interfaccia OrganizationUnit e crea una classeDepartmentche la implementa. Un reparto è un composito che può contenere sia dipendenti sia altri reparti. Il tuo reparto dovrebbe:- Accettare un nome nel costruttore
- Implementare
getName()per restituire il nome del reparto - Avere un metodo
add(OrganizationUnit $unit): voidper aggiungere dipendenti o sottoreparti - Implementare
getSalary()per restituire lo stipendio totale di tutte le unità contenute (sommando ricorsivamente tutto ciò che si trova al loro interno)
main.php: Includi i file Employee e Department. Riceverai un input: una stringa JSON che rappresenta la struttura dell’organizzazione.Il JSON avrà questo formato:
{"Engineering": [{"name": "Alice", "salary": 80000}, {"name": "Bob", "salary": 75000}], "Sales": [{"name": "Carol", "salary": 65000}]}Ogni chiave è il nome di un reparto e il relativo valore è un array di dipendenti con i rispettivi nomi e stipendi.
Crea un
Departmentradice chiamato"Company". Per ogni reparto nel JSON, crea unDepartment, aggiungi i suoi dipendenti e poi aggiungi quel reparto a Company. Infine, stampa lo stipendio totale dell’azienda in questo formato:Total Salary: [amount]
Il bello del Composite Pattern è che chiamando getSalary() sul reparto Company si calcola automaticamente la somma di tutti i reparti e i dipendenti annidati: il codice client non deve conoscere la struttura interna.
Provalo tu
<?php
require_once 'Employee.php';
require_once 'Department.php';
// Leggi l'input JSON
$input = trim(fgets(STDIN));
$data = (array)json_decode($input, true);
// TODO: Crea un Department radice chiamato "Company"
// TODO: Scorri ogni dipartimento nei dati JSON
// Per ogni dipartimento:
// - Crea un nuovo oggetto Department
// - Aggiungi ogni dipendente a quel dipartimento
// - Aggiungi il dipartimento a Company
// TODO: Stampa lo stipendio totale nel formato: Total Salary: [amount]
?>Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.
Tutte le lezioni di Programmazione orientata agli oggetti
1Fondamenti della programmazione orientata agli oggetti
File esterniIntroduzione alla programmazione orientata agli oggettiClassi e oggettiLa parola chiave $thisMetodiProprietàCostruttore (__construct)Distruttore (__destruct)Riepilogo - Calcolatrice semplice4Ereditarietà
Ereditarietà di baseLa parola chiave parent::Sovrascrittura dei metodiLa parola chiave finalClassi astratteRiepilogo - Gerarchia dei dipendenti7Incapsulamento
Pubblico, Protetto, PrivatoApprofondimento sui modificatori di accessoGetter e SetterOccultamento delle informazioniPromozione dei parametri del costruttore (8.0)Riepilogo - Sistema di gestione dei registri degli studenti10Concetti avanzati di programmazione a oggetti
Composizione vs ereditarietàDependency InjectionClassi anonimeEnumerazioni (PHP 8.1)Fibers (PHP 8.1)Approfondimento sulla clonazione degli oggettiGeneratori e iteratori13Modelli di progettazione, parte 2
Modello CommandModello AdapterModello DecoratorModello Template MethodModello StateModello CompositeModello Repository2Namespace e autoloading
Introduzione ai namespaceLa keyword useStandard di autoloading PSR-4Autoloader di ComposerRiepilogo - Progetto organizzato5Interfacce e contratti
Introduzione alle interfacceImplementare le interfacceImplementare più interfacceInterfaccia vs classe astrattaType hinting con le interfacceRiepilogo - Calcolatore di forme8Metodi magici
Introduzione ai metodi magici__toString e __debugInfo__get, __set, __isset, __unset__call e __callStatic__clone e clonazione degli oggetti__serialize e __unserializeRiepilogo - Collezione personalizzata11Sistema dei tipi e gestione degli errori
Dichiarazioni di tipoTipi nullableTipi unione e intersezioneClassi di eccezioneGerarchia di eccezioni personalizzataTry, Catch, FinallyRiepilogo - Validatore di moduli14Progetto: Gestione della biblioteca
Panoramica del progettoClassi Libro e Utente3Proprietà delle classi
Proprietà di istanza e staticheCostanti nelle classiMetodi e proprietà staticiProprietà private e protectedProprietà readonly (PHP 8.1)Riepilogo - Gestore di conti bancari6Polimorfismo
Ridefinizione dei metodi, ripresaPolimorfismo tramite interfacceSuggerimenti sui tipi e tipi UnionBinding statico tardivoRiepilogo - Processore di pagamenti9Tratti
Introduzione ai trattiUtilizzare più trattiRisoluzione dei conflitti tra trattiMetodi astratti nei trattiTratti vs ereditarietà12Design pattern - Parte 1
Introduzione ai design patternPattern SingletonPattern FactoryPattern ObserverPattern StrategyEsercitati da solo: Compilatore PHP online