Wzorzec metody szablonowej
Część sekcji Programowanie obiektowe ścieżki PHP w Coddy. Lekcja 78 z 91.
Wzorzec Template Method to behawioralny wzorzec projektowy, który definiuje szkielet algorytmu w klasie bazowej, pozwalając klasom pochodnym nadpisywać określone kroki bez zmieniania ogólnej struktury. Klasa bazowa kontroluje przebieg pracy, a klasy pochodne dostosowują poszczególne elementy.
Rozważ tworzenie różnych typów dokumentów.
Każdy dokument przechodzi przez ten sam proces: utworzenie nagłówka, dodanie treści, utworzenie stopki. Szczegóły każdego kroku różnią się jednak w zależności od typu dokumentu. Metoda szablonowa definiuje tę sekwencję, a podklasy implementują poszczególne szczegóły.
<?php
abstract class DocumentGenerator {
// Metoda szablonowa – definiuje strukturę algorytmu
public final function generate(): string {
$output = $this->createHeader();
$output .= $this->createContent();
$output .= $this->createFooter();
return $output;
}
// Kroki do zaimplementowania przez klasy pochodne
abstract protected function createHeader(): string;
abstract protected function createContent(): string;
abstract protected function createFooter(): string;
}
class HtmlDocument extends DocumentGenerator {
protected function createHeader(): string {
return "<html><head></head><body>";
}
protected function createContent(): string {
return "<p>Hello World</p>";
}
protected function createFooter(): string {
return "</body></html>";
}
}
class TextDocument extends DocumentGenerator {
protected function createHeader(): string {
return "=== DOCUMENT ===\n";
}
protected function createContent(): string {
return "Hello World\n";
}
protected function createFooter(): string {
return "=== END ===";
}
}
$html = new HtmlDocument();
echo $html->generate() . "\n";
$text = new TextDocument();
echo $text->generate();
Wynik:
<html><head></head><body><p>Hello World</p></body></html>
=== DOCUMENT ===
Hello World
=== END ===Zwróć uwagę na słowo kluczowe final w metodzie szablonowej. Zapobiega ono zmianie struktury algorytmu przez podklasy. Ten wzorzec sprawdza się idealnie, gdy masz wiele klas realizujących ten sam przepływ pracy, ale różniących się szczegółami implementacji. Dodanie nowego typu dokumentu oznacza utworzenie nowej podklasy bez ingerowania w istniejący kod.
Wyzwanie
ŁatwyZbudujmy system generowania raportów z użyciem wzorca Template Method. Różne typy raportów mają tę samą strukturę: sekcję tytułu, sekcję danych i sekcję podsumowania, ale każdy typ raportu formatuje te sekcje inaczej. Metoda szablonowa zdefiniuje ten przepływ, a podklasy dostosują poszczególne kroki.
Rozmieścisz kod w czterech plikach:
ReportGenerator.php: Utwórz abstrakcyjną klasęReportGenerator, która definiuje szkielet algorytmu generowania raportu. Twoja klasa powinna:- Przyjmować tytuł raportu w konstruktorze (użyj promocji właściwości konstruktora)
- Mieć publiczną metodę
finalgenerate(): string, która wywołuje kolejno trzy kroki:createTitle(),createBody()icreateSummary(), łącząc ich wyniki - Deklarować trzy abstrakcyjne metody chronione, które podklasy muszą zaimplementować:
createTitle(): string,createBody(): stringicreateSummary(): string
HtmlReport.php: Dołącz plik ReportGenerator i utwórz klasęHtmlReport, która ją rozszerza. Ten raport formatuje dane wyjściowe jako HTML:createTitle()zwraca"<h1>[title]</h1>"createBody()zwraca"<p>Report data goes here</p>"createSummary()zwraca"<footer>End of report</footer>"
PlainTextReport.php: Dołącz plik ReportGenerator i utwórz klasęPlainTextReport, która ją rozszerza. Ten raport używa prostego formatowania tekstu:createTitle()zwraca"### [title] ###\n"createBody()zwraca"Report data goes here\n"createSummary()zwraca"--- End of report ---"
main.php: Dołącz oba pliki raportów. Otrzymasz dwa dane wejściowe: typ raportu ("html"lub"text") oraz tytuł raportu.Na podstawie typu raportu utwórz odpowiedni generator raportów z podanym tytułem. Wywołaj
generate()i wypisz cały raport.
Wzorzec Template Method sprawia, że wszystkie raporty mają tę samą, trzyetapową strukturę, a jednocześnie pozwala każdemu typowi raportu w unikalny sposób formatować swoje sekcje. Słowo kluczowe final w metodzie generate() uniemożliwia podklasom zmianę kolejności algorytmu. Mogą one dostosowywać wyłącznie poszczególne kroki.
Spróbuj swoich sił
<?php
require_once 'HtmlReport.php';
require_once 'PlainTextReport.php';
// Wczytaj dane wejściowe
$reportType = trim(fgets(STDIN));
$reportTitle = trim(fgets(STDIN));
// TODO: Na podstawie typu raportu ("html" lub "text"),
// utwórz odpowiedni generator raportu z podanym tytułem
// TODO: Wywołaj generate() i wypisz cały raport
?>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