Schablonenmethodenmuster
Teil des Abschnitts Objektorientierte Programmierung der Java-Journey von Coddy. Lektion 73 von 87.
Das Template-Method-Muster ist ein Verhaltensentwurfsmuster, das das Grundgerüst eines Algorithmus in einer Basisklasse definiert und es Unterklassen ermöglicht, bestimmte Schritte zu überschreiben, ohne die Gesamtstruktur zu ändern. Stell es dir wie ein Rezept vor: Der allgemeine Kochprozess bleibt gleich, aber einzelne Zutaten oder Techniken können variieren.
Das Muster verwendet eine abstrakte Klasse mit einer Vorlagenmethode, die eine Folge von Schritten aufruft. Einige Schritte haben Standardimplementierungen, während andere abstrakt sind und von Unterklassen implementiert werden müssen:
abstract class DataProcessor {
// Template-Methode – definiert die Struktur des Algorithmus
public final void process() {
readData();
processData();
saveData();
}
abstract void readData();
abstract void processData();
// Standardimplementierung (Hook-Methode)
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");
}
}Die Template-Methode wird typischerweise als final markiert, um zu verhindern, dass Unterklassen die Struktur des Algorithmus verändern. Beim Aufruf führt sie für alle Unterklassen dieselbe Abfolge aus:
DataProcessor csv = new CSVProcessor();
csv.process();
// Ausgabe:
// CSV-Datei lesen
// CSV-Daten parsen
// Speichern am StandardortDas Template-Method-Muster ist ideal, wenn du Algorithmen hast, die dieselbe Struktur aufweisen, sich aber in bestimmten Schritten unterscheiden. Es fördert die Wiederverwendung von Code, indem gemeinsame Logik in der Basisklasse platziert wird und gleichzeitig eine Anpassung durch Vererbung ermöglicht wird.
Aufgabe
EinfachErstellen wir ein Dokumentgenerierungssystem mit dem Template Method Pattern! Du erstellst ein Framework, in dem verschiedene Dokumenttypen (Berichte und Rechnungen) demselben Generierungsprozess folgen, aber bestimmte Schritte anpassen. Das ist ideal für Szenarien, in denen der allgemeine Ablauf feststeht, die Details jedoch je nach Dokumenttyp variieren.
Du organisierst deinen Code auf vier Dateien verteilt:
DocumentGenerator.java: Erstelle die abstrakte Basisklasse, die die Template-Methode definiert. DeineDocumentGenerator-Klasse sollte Folgendes enthalten:Eine
final-Methode namensgenerateDocument(), die das Grundgerüst des Algorithmus definiert, indem sie drei Schritte in dieser Reihenfolge aufruft:createHeader(),createBody()undcreateFooter().Zwei abstrakte Methoden:
createHeader()undcreateBody(), die von Unterklassen implementiert werden müssen.Eine Hook-Methode
createFooter()mit einer Standardimplementierung, die--- End of Document ---ausgibt.ReportGenerator.java: Erstelle eine konkrete Unterklasse zum Generieren von Berichten. Sie sollte über ihren Konstruktor einen Berichtstitel (String) entgegennehmen.Die Methode
createHeader()gibt=== REPORT: [title] ===aus.Die Methode
createBody()gibtReport content goes here...aus.Verwende den geerbten Standard-Footer.
InvoiceGenerator.java: Erstelle eine weitere konkrete Unterklasse zum Generieren von Rechnungen. Sie sollte über ihren Konstruktor einen Kundennamen (String) und einen Betrag (double) entgegennehmen.Die Methode
createHeader()gibt*** INVOICE ***aus.Die Methode
createBody()gibt in einer ZeileCustomer: [name]und in der nächsten ZeileAmount Due: $[amount]aus (formatiere den Betrag mit zwei Dezimalstellen).Überschreibe
createFooter(), umThank you for your business!auszugeben.Main.java: Führe dein Template-Method-System zusammen! Du erhältst drei Eingaben: einen Berichtstitel (String), einen Kundennamen (String) und einen Rechnungsbetrag (double).Erstelle einen
ReportGeneratormit dem Titel und rufegenerateDocument()auf. Gib zur Trennung eine leere Zeile aus. Erstelle anschließend einenInvoiceGeneratormit dem Kundennamen und dem Betrag und rufegenerateDocument()auf.
Du erhältst drei Eingaben in dieser Reihenfolge: Berichtstitel (String), Kundenname (String) und Rechnungsbetrag (double).
Bei den Eingaben Q4 Sales, Acme Corp und 1500.00 würde deine Ausgabe beispielsweise folgendermaßen aussehen:
=== REPORT: Q4 Sales ===
Report content goes here...
--- End of Document ---
*** INVOICE ***
Customer: Acme Corp
Amount Due: $1500.00
Thank you for your business!Beachte, wie beide Dokumenttypen demselben dreistufigen Prozess folgen, der in der Template-Methode definiert ist, aber die einzelnen Schritte jeweils unterschiedlich anpassen. ReportGenerator verwendet den Standard-Footer, während InvoiceGenerator einen eigenen bereitstellt. Das ist die Stärke von Hook-Methoden im Template Method Pattern!
Probier es selbst
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// Eingaben lesen
String reportTitle = scanner.nextLine();
String customerName = scanner.nextLine();
double invoiceAmount = scanner.nextDouble();
// TODO: Erstelle einen ReportGenerator mit dem Titel und rufe generateDocument() auf
// TODO: Gib eine leere Zeile zur Trennung aus
// TODO: Erstelle einen InvoiceGenerator mit Kundenname und Betrag und rufe generateDocument() auf
}
}
Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Objektorientierte Programmierung
1Grundlagen der OOP
Externe DateienEinführung in die OOPKlassen vs. ObjekteDas Schlüsselwort thisMethodenFelder (Attribute)KonstruktormethodeÜberladen von KonstruktorenRückblick – Einfacher Taschenrechner4Vererbung
Grundlegende Vererbung (extends)Das Schlüsselwort superÜberschreiben von Methoden (@Override)KonstruktorverkettungDie Object-KlasseEinfach- und mehrstufige VererbungWarum keine Mehrfachvererbung von KlassenRückblick – Mitarbeiterhierarchie7Spezielle Methoden & Object-Klasse
toString()-Methodeequals() und hashCode()clone()-MethodecompareTo() und ComparableComparator-SchnittstelleRückblick – Benutzerdefinierte Sortierung2Zugriffsmodifikatoren & Kapselung
Übersicht der ZugriffsebenenGetter- und Setter-MethodenInformationsverbergungDas Schlüsselwort finalRückblick – Bankkontoverwaltung5Polymorphismus
Grundlagen der MethodenüberladungMethodenüberschreibung (Laufzeit)Upcasting und DowncastingDer instanceof-OperatorAbstrakte Klassen und MethodenRückblick – Formrechner8Fortgeschrittene OOP-Konzepte
Komposition vs. VererbungAggregation vs. KompositionInnere, verschachtelte & anonyme KlassenEnums und Enum-MethodenRecords (Java 16+)Versiegelte Klassen (Java 17+)11Entwurfsmuster Teil 1
Einführung in EntwurfsmusterSingleton-MusterFactory-MusterBuilder-MusterObserver-MusterStrategie-Muster14Abschließende Herausforderungen
E-Learning-PlattformBankingsystemEntwicklung einer SpielfigurFahrzeugvermietungsdienst3Klassen-Props & statische Member
Instanz- vs. statische VariablenStatische MethodenStatische BlöckeKonstanten (static final)Wiederholung – Counter & Utility6Schnittstellen & abstrakte Klassen
Einführung in InterfacesInterfaces implementierenMehrere Interfaces implementierenDefault & Static in InterfacesAbstrakte Klassen vs. InterfacesFunktionale InterfacesRückblick – Zahlungssystem9Generics
Einführung in GenericsGenerische KlassenGenerische MethodenGebundene TypparameterWildcards (?, extends, super)Rückblick – Generischer Container12Entwurfsmuster Teil 2
BefehlsmusterAdaptermusterDekorierermusterSchablonenmethodenmusterZustandsmusterKompositmusterIteratormusterÜbe selbstständig: Online-Java-Compiler