Wzorzec kompozytu
Część sekcji Programowanie obiektowe ścieżki PHP w Coddy. Lekcja 80 z 91.
Wzorzec Kompozyt to strukturalny wzorzec projektowy, który pozwala łączyć obiekty w struktury drzewiaste, a następnie pracować z nimi tak, jakby były pojedynczymi obiektami. Doskonale nadaje się do przedstawiania hierarchii część–całość, w których pojedyncze obiekty i grupy obiektów mają być traktowane jednolicie.
Rozważ system plików. Folder może zawierać pliki i inne foldery.
Podczas obliczania łącznego rozmiaru chcesz wywoływać tę samą metodę zarówno dla plików, jak i folderów, a foldery powinny rekurencyjnie sumować rozmiary swojej zawartości. Wzorzec Kompozyt zapewnia płynne działanie, udostępniając liściom (plikom) i kompozytom (folderom) ten sam interfejs.
<?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;
}
}
Teraz możesz tworzyć struktury drzewiaste i traktować je jednolicie:
<?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();
Wynik:
1810Kod klienta wywołuje getSize(), nie przejmując się tym, czy ma do czynienia z pojedynczym plikiem, czy z głęboko zagnieżdżoną strukturą folderów. Wzorzec obsługuje rekurencję wewnętrznie, dzięki czemu praca ze złożonymi hierarchiami jest łatwa.
Wyzwanie
ŁatwyZbudujmy system schematu organizacyjnego z wykorzystaniem wzorca Composite. Firmy mają hierarchiczną strukturę, w której działy mogą zawierać pracowników i inne poddziały: to idealna struktura drzewa, w której chcesz jednolicie obliczać sumy dla całej organizacji.
Rozmieścisz swój kod w czterech plikach:
OrganizationUnit.php: Zdefiniuj interfejsOrganizationUnit, który będą implementować zarówno pojedynczy pracownicy, jak i działy. Powinien zawierać dwie metody:getName(): stringigetSalary(): int. Ten wspólny interfejs pozwala traktować pojedynczych pracowników i całe działy w ten sam sposób podczas obliczania kosztów.Employee.php: Dołącz interfejs OrganizationUnit i utwórz klasęEmployee, która go implementuje. Pracownik jest węzłem liściowym w drzewie organizacji. Ma imię i wynagrodzenie, ale nie może zawierać innych jednostek. Użyj promocji konstruktora, aby przyjąć imię i wynagrodzenie, i zaimplementuj obie metody interfejsu.Department.php: Dołącz interfejs OrganizationUnit i utwórz klasęDepartment, która go implementuje. Dział jest kompozytem, który może zawierać zarówno pracowników, jak i inne działy. Twój dział powinien:- Przyjmować nazwę w konstruktorze
- Implementować
getName(), aby zwracać nazwę działu - Mieć metodę
add(OrganizationUnit $unit): void, która dodaje pracowników lub poddziały - Implementować
getSalary(), aby zwracać łączne wynagrodzenie wszystkich zawartych w nim jednostek (rekurencyjnie sumując wszystko, co się w nim znajduje)
main.php: Dołącz pliki Employee i Department. Otrzymasz jedno wejście: ciąg JSON reprezentujący strukturę organizacji.JSON będzie mieć następujący format:
{"Engineering": [{"name": "Alice", "salary": 80000}, {"name": "Bob", "salary": 75000}], "Sales": [{"name": "Carol", "salary": 65000}]}Każdy klucz to nazwa działu, a jego wartością jest tablica pracowników wraz z ich imionami i wynagrodzeniami.
Utwórz główny
Departmento nazwie"Company". Dla każdego działu w JSON utwórzDepartment, dodaj do niego pracowników, a następnie dodaj ten dział do Company. Na koniec wyświetl łączne wynagrodzenie firmy w następującym formacie:Total Salary: [amount]
Zaletą wzorca Composite jest to, że wywołanie getSalary() na dziale Company automatycznie oblicza sumę wynagrodzeń ze wszystkich zagnieżdżonych działów i pracowników: kod klienta nie musi znać wewnętrznej struktury.
Spróbuj swoich sił
<?php
require_once 'Employee.php';
require_once 'Department.php';
// Odczytaj dane wejściowe JSON
$input = trim(fgets(STDIN));
$data = (array)json_decode($input, true);
// TODO: Utwórz główny obiekt Department o nazwie "Company"
// TODO: Przejdź przez każdy dział w danych JSON
// Dla każdego działu:
// - Utwórz nowy obiekt Department
// - Dodaj każdego pracownika do tego działu
// - Dodaj dział do Company
// TODO: Wypisz łączną kwotę wynagrodzeń w formacie: Total Salary: [amount]
?>Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.
Wszystkie lekcje w sekcji Programowanie obiektowe
1Podstawy programowania obiektowego
Pliki zewnętrzneWprowadzenie do programowania obiektowegoKlasy a obiektySłowo kluczowe $thisMetodyWłaściwościKonstruktor (__construct)Destruktor (__destruct)Powtórka — prosty kalkulator4Dziedziczenie
Podstawy dziedziczeniaSłowo kluczowe parent::Przesłanianie metodSłowo kluczowe finalKlasy abstrakcyjnePowtórzenie – hierarchia pracowników7Enkapsulacja
Public, protected, privateModyfikatory dostępu w szczegółachGettery i setteryUkrywanie informacjiPromocja parametrów konstruktora (8.0)Podsumowanie — system ewidencji studentów10Zaawansowane koncepcje OOP
Kompozycja a dziedziczenieWstrzykiwanie zależnościKlasy anonimoweEnumy (PHP 8.1)Włókna (PHP 8.1)Dogłębne omówienie klonowania obiektówGeneratory i iteratory13Wzorce projektowe, część 2
Wzorzec poleceniaWzorzec adapteraWzorzec dekoratoraWzorzec metody szablonowejWzorzec stanuWzorzec kompozytuWzorzec repozytorium2Przestrzenie nazw i autoloading
Wprowadzenie do przestrzeni nazwSłowo kluczowe useStandard autoloadingu PSR-4Autoloader ComposeraPodsumowanie – uporządkowany projekt5Interfejsy i kontrakty
Wprowadzenie do interfejsówImplementowanie interfejsówImplementowanie wielu interfejsówInterfejs a klasa abstrakcyjnaPodpowiadanie typów za pomocą interfejsówPodsumowanie — kalkulator kształtów8Metody magiczne
Wprowadzenie do metod magicznych__toString i __debugInfo__get, __set, __isset, __unset__call i __callStatic__clone i klonowanie obiektów__serialize i __unserializePodsumowanie — własna kolekcja11System typów i obsługa błędów
Deklaracje typówTypy nullableTypy sumy i przecięciaKlasy wyjątkówNiestandardowa hierarchia wyjątkówTry, Catch, FinallyPodsumowanie — walidator formularzy14Projekt: Zarządzanie biblioteką
Przegląd projektuKlasy książki i użytkownika3Właściwości klas
Właściwości instancji a właściwości statyczneStałe w klasachMetody i właściwości statyczneWłaściwości prywatne i chronioneWłaściwości tylko do odczytu (PHP 8.1)Podsumowanie — menedżer kont bankowych6Polimorfizm
Ponowne omówienie nadpisywania metodPolimorfizm za pomocą interfejsówPodpowiedzi typów i typy sumyPóźne wiązanie statycznePodsumowanie — procesor płatności9Cechy
Wprowadzenie do cechKorzystanie z wielu cechRozwiązywanie konfliktów cechMetody abstrakcyjne w cechachCechy a dziedziczenie12Wzorce projektowe, część 1
Wprowadzenie do wzorców projektowychWzorzec SingletonWzorzec FactoryWzorzec ObserverWzorzec StrategyPoćwicz samodzielnie: Kompilator PHP online