Vorlagenmethodenmuster
Teil des Abschnitts Objektorientierte Programmierung der C#-Journey von Coddy. Lektion 59 von 70.
Das Template-Method-Muster ist ein Verhaltensmuster, das das Grundgerüst eines Algorithmus in einer Basisklasse definiert und Unterklassen ermöglicht, bestimmte Schritte zu überschreiben, ohne die Gesamtstruktur zu ändern. Die Basisklasse steuert den Ablauf, während abgeleitete Klassen einzelne Bestandteile anpassen.
Dieses Muster verwendet Vererbung und abstrakte Methoden. Die Basisklasse enthält eine „Vorlagenmethode“, die eine Abfolge von Schritten aufruft, von denen einige abstrakt sind und von Unterklassen implementiert werden müssen:
public abstract class DataProcessor
{
// Template-Methode - definiert die Struktur des Algorithmus
public void Process()
{
ReadData();
ProcessData();
SaveData();
}
protected abstract void ReadData();
protected abstract void ProcessData();
protected virtual void SaveData() => Console.WriteLine("Saving to default location");
}
public class CsvProcessor : DataProcessor
{
protected override void ReadData() => Console.WriteLine("Reading CSV file");
protected override void ProcessData() => Console.WriteLine("Parsing CSV data");
}
public class JsonProcessor : DataProcessor
{
protected override void ReadData() => Console.WriteLine("Reading JSON file");
protected override void ProcessData() => Console.WriteLine("Parsing JSON data");
protected override void SaveData() => Console.WriteLine("Saving to cloud");
}Jede Unterklasse stellt ihre eigene Implementierung bereit, während die Basisklasse die Reihenfolge der Operationen festlegt:
DataProcessor csv = new CsvProcessor();
csv.Process();
// CSV-Datei lesen
// CSV-Daten parsen
// Saving to default location
DataProcessor json = new JsonProcessor();
json.Process();
// JSON-Datei lesen
// JSON-Daten parsen
// In die Cloud speichernDas Template-Method-Muster ist ideal, wenn mehrere Klassen dieselbe Algorithmusstruktur aufweisen, sich aber in bestimmten Schritten unterscheiden. Es fördert die Wiederverwendung von Code, indem die gemeinsame Logik in der Basisklasse platziert wird und gleichzeitig durch überschreibbare Methoden Flexibilität ermöglicht wird.
Aufgabe
EinfachErstellen wir ein Berichtsgenerierungssystem mithilfe des Template-Method-Musters. Verschiedene Berichtstypen (z. B. Verkaufsberichte und Lagerbestandsberichte) haben dieselbe übergeordnete Struktur – sie müssen alle Daten sammeln, sie formatieren und das Ergebnis ausgeben –, aber jeder Berichtstyp verarbeitet diese Schritte unterschiedlich.
Du organisierst deinen Code auf drei Dateien verteilt:
ReportGenerator.cs: Erstelle eine abstrakte KlasseReportGeneratorim NamespaceReporting. Diese Basisklasse definiert das Grundgerüst des Algorithmus zur Berichtsgenerierung durch eine Template-Methode namensGenerate(). Die Methode soll drei Schritte der Reihe nach aufrufen:GatherData(),FormatReport()undOutputReport(). MacheGatherData()undFormatReport()abstrakt (jeder Berichtstyp implementiert diese unterschiedlich), währendOutputReport()eine virtuelle Methode mit einer Standardimplementierung sein soll, dieSending to default printerausgibt.ConcreteReports.cs: Erstelle zwei konkrete Berichtsklassen im selben Namespace, die vonReportGeneratorerben:SalesReport– implementiertGatherData(), umCollecting sales data from databaseauszugeben, undFormatReport(), umFormatting as sales summaryauszugebenInventoryReport– implementiertGatherData(), umScanning warehouse inventoryauszugeben,FormatReport(), umFormatting as inventory listauszugeben, und überschreibtOutputReport(), umSending to warehouse managerauszugeben
Program.cs: Führe alles zusammen, indem du Berichtinstanzen erstellst und sie generierst. Die Template-Methode stellt sicher, dass jeder Bericht denselben dreistufigen Prozess durchläuft, aber das konkrete Verhalten jedes Schritts variiert je nach Berichtstyp.
Du erhältst eine Eingabe:
- Der Berichtstyp:
salesoderinventory
Erstelle anhand der Eingabe den passenden Berichtsgenerator und rufe seine Methode Generate() auf.
Wenn die Eingabe beispielsweise sales lautet, sollte die Ausgabe wie folgt aussehen:
Collecting sales data from database
Formatting as sales summary
Sending to default printerWenn die Eingabe inventory lautet, sollte die Ausgabe wie folgt aussehen:
Scanning warehouse inventory
Formatting as inventory list
Sending to warehouse managerBeachte, dass beide Berichte exakt derselben Algorithmusstruktur folgen (sammeln, formatieren, ausgeben), die Implementierung jedes Schritts jedoch angepasst ist. SalesReport verwendet das standardmäßige Ausgabeverhalten, während InventoryReport es überschreibt – damit wird veranschaulicht, wie du mit dem Template-Method-Muster festlegen kannst, welche Schritte zwingend überschrieben werden müssen und welche optional angepasst werden können!
Probier es selbst
using System;
using Reporting;
class Program
{
public static void Main(string[] args)
{
string reportType = Console.ReadLine();
// TODO: Erstelle den entsprechenden Berichtsgenerator basierend auf reportType
// Wenn reportType "sales" ist, erstelle einen SalesReport
// Wenn reportType "inventory" ist, erstelle einen InventoryReport
// Rufe dann die Generate()-Methode auf dem Bericht 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 DateienNamespaces & DirektivenEinführung in Klassen & ObjekteDas 'this'-SchlüsselwortMethoden und ParameterFelder vs. EigenschaftenKonstruktorenObjektinitialisiererWiederholung – Einfacher Taschenrechner4Vererbung
Grundlegende Vererbungs-(:)-SyntaxDas „base“-Schlüsselwort„virtual“- und „override“-SchlüsselwörterVersiegelte KlassenDie „object“-BasisklasseWiederholung – Mitarbeiterhierarchie7Erweiterte Funktionen
Überladen von OperatorenIndexer (this[])ToString()-ÜberschreibungErweiterungsmethodenRückblick – Benutzerdefinierte Liste10Entwurfsmuster Teil 1
Einführung in EntwurfsmusterThread-sicheres SingletonFactory-MusterObserver-Muster (Events)Strategy-Muster13Abschließende Herausforderungen
E-Learning-PlattformKomponente für SpielfigurenFahrzeugvermietungsdienst2Eigenschaften & statische Member
Automatisch implementierte EigenschaftenNur lesbare/schreibbare EigenschaftenStatische Felder & MethodenStatische KlassenMember mit Ausdruckskörpern5Polymorphie & Interfaces
Compile- vs. Laufzeit-PolymorphieInterface vs. abstrakte KlasseMehrere InterfacesExplizite InterfacesUpcasting & DowncastingWiederholung – Formenrechner8Fortgeschrittene OOP-Konzepte
Komposition statt VererbungGenerics (Klassen & Methoden)Delegates und EventsAttribute und ReflectionIDisposable & using-AnweisungGrundlagen der Dependency Injection11Entwurfsmuster Teil 2
BefehlsmusterAdaptermusterDekorierermusterVorlagenmethodenmusterZustandsmusterKompositumsmuster3Klassenarchitektur
Instanz- vs. statische DatenSchlüsselwörter 'readonly' & 'const'Backing FieldsRückblick – Bankkontenverwaltung6Kapselung
ZugriffsmodifikatorenEigenschaften zur KapselungImplementierung der DatenkapselungMuster für UnveränderlichkeitRückblick – SchülerdatenÜbe selbstständig: Online-C#-Compiler