Wzorzec metody szablonowej
Część sekcji Programowanie obiektowe ścieżki Java w Coddy. Lekcja 73 z 87.
Wzorzec metody szablonowej to behawioralny wzorzec projektowy, który definiuje szkielet algorytmu w klasie bazowej, umożliwiając podklasom nadpisywanie konkretnych kroków bez zmiany ogólnej struktury. Pomyśl o tym jak o przepisie: ogólny proces gotowania pozostaje taki sam, ale poszczególne składniki lub techniki mogą się różnić.
Wzorzec wykorzystuje klasę abstrakcyjną z metodą szablonową, która wywołuje sekwencję kroków. Niektóre kroki mają domyślne implementacje, podczas gdy inne są abstrakcyjne i muszą zostać zaimplementowane przez podklasy:
abstract class DataProcessor {
// Metoda szablonowa - definiuje strukturę algorytmu
public final void process() {
readData();
processData();
saveData();
}
abstract void readData();
abstract void processData();
// Domyślna implementacja (metoda hakowa)
void saveData() {
System.out.println("Saving to default location");
}
}
class CSVProcessor extends DataProcessor {
void readData() {
System.out.println("Reading CSV file");
}
void processData() {
System.out.println("Parsing CSV data");
}
}
class XMLProcessor extends DataProcessor {
void readData() {
System.out.println("Reading XML file");
}
void processData() {
System.out.println("Parsing XML data");
}
}Metoda szablonowa jest zazwyczaj oznaczana jako final, aby zapobiec zmianie struktury algorytmu przez podklasy. Po wywołaniu wykonuje tę samą sekwencję dla wszystkich podklas:
DataProcessor csv = new CSVProcessor();
csv.process();
// Wynik:
// Odczytywanie pliku CSV
// Przetwarzanie danych CSV
// Zapisywanie w domyślnej lokalizacjiWzorzec Metody Szablonowej sprawdza się idealnie, gdy masz algorytmy o tej samej strukturze, ale różniące się poszczególnymi krokami. Ułatwia ponowne wykorzystanie kodu, umieszczając wspólną logikę w klasie bazowej i umożliwiając dostosowywanie jej za pomocą dziedziczenia.
Wyzwanie
ŁatwyZbudujmy system generowania dokumentów z użyciem wzorca metody szablonowej! Utworzysz strukturę, w której różne typy dokumentów (raporty i faktury) są generowane według tego samego procesu, ale poszczególne kroki są dostosowywane do ich typu. To idealne rozwiązanie w sytuacjach, gdy ogólny przepływ pracy jest stały, ale szczegóły różnią się w zależności od typu dokumentu.
Rozmieścisz kod w czterech plikach:
DocumentGenerator.java: Utwórz abstrakcyjną klasę bazową, która definiuje metodę szablonową. Twoja klasaDocumentGeneratorpowinna mieć:Metodę
finalo nazwiegenerateDocument(), która definiuje szkielet algorytmu, wywołując kolejno trzy kroki:createHeader(),createBody()icreateFooter().Dwie metody abstrakcyjne:
createHeader()icreateBody(), które podklasy muszą zaimplementować.Metodę hakową
createFooter()z domyślną implementacją, która wyświetla--- End of Document ---.ReportGenerator.java: Utwórz konkretną podklasę do generowania raportów. Jej konstruktor powinien przyjmować tytuł raportu (String).Metoda
createHeader()wyświetla=== REPORT: [title] ===Metoda
createBody()wyświetlaReport content goes here...Użyj odziedziczonej domyślnej stopki.
InvoiceGenerator.java: Utwórz kolejną konkretną podklasę do generowania faktur. Jej konstruktor powinien przyjmować nazwę klienta (String) i kwotę (double).Metoda
createHeader()wyświetla*** INVOICE ***Metoda
createBody()wyświetlaCustomer: [name]w jednym wierszu, a następnieAmount Due: $[amount]w kolejnym wierszu (sformatuj kwotę do dwóch miejsc po przecinku).Nadpisz metodę
createFooter(), aby wyświetlałaThank you for your business!Main.java: Połącz elementy systemu metody szablonowej! Otrzymasz trzy dane wejściowe: tytuł raportu (String), nazwę klienta (String) i kwotę faktury (double).Utwórz obiekt
ReportGeneratorz tytułem i wywołajgenerateDocument(). Wyświetl pusty wiersz jako separator. Następnie utwórz obiektInvoiceGeneratorz nazwą klienta i kwotą, po czym wywołajgenerateDocument().
Otrzymasz kolejno trzy dane wejściowe: tytuł raportu (String), nazwę klienta (String) i kwotę faktury (double).
Na przykład dla danych wejściowych Q4 Sales, Acme Corp i 1500.00 wynik będzie następujący:
=== REPORT: Q4 Sales ===
Report content goes here...
--- End of Document ---
*** INVOICE ***
Customer: Acme Corp
Amount Due: $1500.00
Thank you for your business!Zwróć uwagę, że oba typy dokumentów są generowane według tego samego, zdefiniowanego w metodzie szablonowej procesu składającego się z trzech kroków, ale każdy z nich dostosowuje te kroki inaczej. Klasa ReportGenerator korzysta z domyślnej stopki, a klasa InvoiceGenerator dostarcza własną. Na tym polega siła metod hakowych we wzorcu metody szablonowej!
Spróbuj swoich sił
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// Wczytaj dane wejściowe
String reportTitle = scanner.nextLine();
String customerName = scanner.nextLine();
double invoiceAmount = scanner.nextDouble();
// TODO: Utwórz ReportGenerator z tytułem i wywołaj generateDocument()
// TODO: Wypisz pustą linię jako separator
// TODO: Utwórz InvoiceGenerator z nazwą klienta i kwotą, a następnie wywołaj generateDocument()
}
}
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 thisMetodyPola (atrybuty)Metoda konstruktoraPrzeciążanie konstruktoraPodsumowanie — prosty kalkulator4Dziedziczenie
Podstawy dziedziczenia (extends)Słowo kluczowe superPrzesłanianie metod (@Override)Łańcuch wywołań konstruktorówKlasa ObjectDziedziczenie jedno- i wielopoziomoweDlaczego Java nie obsługuje wielodziedziczenia klasPodsumowanie – hierarchia pracowników7Metody specjalne i klasa Object
Metoda toString()equals() i hashCode()Metoda clone()compareTo() i ComparableInterfejs ComparatorPodsumowanie — własne sortowanie10Obsługa wyjątków w programowaniu obiektowym
Hierarchia klas wyjątkówWłasne wyjątkiBłędy sprawdzane a niesprawdzaneWzorzec try-with-resourcesPodsumowanie – zweryfikowany użytkownik2Modyfikatory dostępu i enkapsulacja
Przegląd poziomów dostępuMetody pobierające i ustawiająceUkrywanie informacjiSłowo kluczowe finalPodsumowanie — menedżer kont bankowych5Polimorfizm
Podstawy przeciążania metodPrzesłanianie metod (w czasie wykonywania)Rzutowanie w górę i w dółOperator instanceofKlasy i metody abstrakcyjnePowtórka — kalkulator figur8Zaawansowane koncepcje OOP
Kompozycja a dziedziczenieAgregacja a kompozycjaKlasy wewnętrzne, zagnieżdżone i anonimoweEnumy i metody enumówRekordy (Java 16+)Klasy zapieczętowane (Java 17+)11Wzorce projektowe — część 1
Wprowadzenie do wzorców projektowychWzorzec SingletonWzorzec FactoryWzorzec BuilderWzorzec ObserverWzorzec Strategy3Właściwości klas i składowe statyczne
Zmienne instancji a zmienne statyczneMetody statyczneBloki statyczneStałe (static final)Powtórka – Counter i Utility6Interfejsy i klasy abstrakcyjne
Wprowadzenie do interfejsówImplementowanie interfejsówImplementacja wielu interfejsówMetody domyślne i statyczne w interfejsieKlasy abstrakcyjne a interfejsyInterfejsy funkcyjnePodsumowanie — system płatności9Typy generyczne
Wprowadzenie do typów generycznychKlasy generyczneMetody generyczneOgraniczone parametry typówSymbole wieloznaczne (?, extends, super)Powtórzenie – kontener generyczny12Wzorce projektowe, część 2
Wzorzec poleceniaWzorzec adapteraWzorzec dekoratoraWzorzec metody szablonowejWzorzec stanuWzorzec kompozytuWzorzec iteratoraPoćwicz samodzielnie: Kompilator Java online