Menu
Coddy logo textTech

Template-Method-Muster

Teil des Abschnitts Objektorientierte Programmierung der Dart-Journey von Coddy — Lektion 97 von 110.

Das Template-Method-Muster definiert das Skelett eines Algorithmus in einer Basisklasse und ermöglicht es Unterklassen, bestimmte Schritte zu überschreiben, ohne die Gesamtstruktur zu ändern. Die Basisklasse steuert den Ablauf, während Unterklassen einzelne Schritte anpassen.

Dieses Muster verwendet Vererbung: Eine abstrakte Klasse definiert eine Template-Methode, die eine Abfolge von Schritten aufruft, von denen einige abstrakt sind (von Unterklassen implementiert werden müssen) und einige Standardimplementierungen haben:

abstract class DataProcessor {
  // Template-Methode - definiert die Algorithmusstruktur
  void process() {
    readData();
    processData();
    saveData();
  }

  void readData();      // Abstrakt - Unterklassen müssen dies implementieren
  void processData();   // Abstrakt - Unterklassen müssen dies implementieren

  void saveData() {     // Standardimplementierung
    print('Data saved to database');
  }
}

class CsvProcessor extends DataProcessor {
  @override
  void readData() => print('Reading CSV file');

  @override
  void processData() => print('Parsing CSV rows');
}

class JsonProcessor extends DataProcessor {
  @override
  void readData() => print('Reading JSON file');

  @override
  void processData() => print('Parsing JSON objects');

  @override
  void saveData() => print('Saved to cloud storage');
}

void main() {
  var csv = CsvProcessor();
  csv.process();
  // Lesen der CSV-Datei
  // Parsen der CSV-Zeilen
  // Daten in der Datenbank gespeichert

  var json = JsonProcessor();
  json.process();
  // Lesen der JSON-Datei
  // Parsen der JSON-Objekte
  // Im Cloud-Speicher gespeichert
}

Die process()-Methode ist das Template – sie definiert die Reihenfolge der Operationen. Unterklassen implementieren readData() und processData() unterschiedlich und können optional saveData() überschreiben. Der entscheidende Vorteil ist, dass die Struktur des Algorithmus über alle Implementierungen hinweg konsistent bleibt, während Flexibilität in den einzelnen Schritten ermöglicht wird.

challenge icon

Aufgabe

Einfach

Lassen Sie uns ein Berichtserstellungssystem mit dem Template Method Pattern erstellen! Sie werden ein Framework entwickeln, in dem verschiedene Arten von Berichten derselben Gesamtstruktur folgen, aber jeder Berichtstyp spezifische Schritte wie die Datenerfassung und die Formatierung der Ausgabe anpasst.

Sie werden Ihren Code in zwei Dateien organisieren:

  • report_generator.dart: Diese Datei enthält Ihre abstrakte Basisklasse und die konkreten Berichtsimplementierungen. Erstellen Sie eine abstrakte Klasse ReportGenerator mit einer Template-Methode namens generate(), die den Workflow der Berichtserstellung in dieser Reihenfolge definiert: fetchData(), analyzeData(), formatReport() und deliver(). Die Methoden fetchData() und formatReport() sollten abstrakt sein (jeder Berichtstyp handhabt diese unterschiedlich), während analyzeData() standardmäßig Analyzing data... und deliver() standardmäßig Report delivered via email. ausgeben sollte. Erstellen Sie dann zwei konkrete Berichtsklassen:
    • SalesReport - dessen fetchData() gibt Fetching sales data from database... aus und dessen formatReport() gibt Formatting as bar charts and tables. aus.
    • InventoryReport - dessen fetchData() gibt Fetching inventory levels from warehouse... aus, dessen formatReport() gibt Formatting as inventory list. aus und es überschreibt deliver(), um Report sent to warehouse manager. auszugeben.
  • main.dart: Importieren Sie Ihre Berichtserstellungsdatei und demonstrieren Sie, wie das Template Method Pattern die Algorithmusstruktur konsistent hält und gleichzeitig Anpassungen ermöglicht. Erstellen Sie einen SalesReport und rufen Sie dessen Methode generate() auf. Geben Sie dann eine Leerzeile zur Trennung aus. Erstellen Sie einen InventoryReport und rufen Sie ebenfalls dessen Methode generate() auf.

Beachten Sie, wie beide Berichte demselben vierstufigen Prozess folgen, aber jeder die Schritte anpasst, die für seinen spezifischen Zweck wichtig sind. Der InventoryReport überschreibt sogar die Standard-Zustellungsmethode, um Berichte an einen anderen Empfänger zu senden!

Erwartete Ausgabe:

Fetching sales data from database...
Analyzing data...
Formatting as bar charts and tables.
Report delivered via email.

Fetching inventory levels from warehouse...
Analyzing data...
Formatting as inventory list.
Report sent to warehouse manager.

Spickzettel

Das Template Method Pattern (Schablonenmethode) definiert das Skelett eines Algorithmus in einer Basisklasse und ermöglicht es Unterklassen, bestimmte Schritte zu überschreiben, ohne die Gesamtstruktur zu ändern.

Eine abstrakte Klasse definiert eine Template-Methode, die eine Abfolge von Schritten aufruft. Einige Schritte sind abstrakt (müssen von Unterklassen implementiert werden) und einige haben Standardimplementierungen:

abstract class DataProcessor {
  // Template-Methode - definiert die Algorithmusstruktur
  void process() {
    readData();
    processData();
    saveData();
  }

  void readData();      // Abstrakt - Unterklassen müssen dies implementieren
  void processData();   // Abstrakt - Unterklassen müssen dies implementieren

  void saveData() {     // Standardimplementierung
    print('Data saved to database');
  }
}

class CsvProcessor extends DataProcessor {
  @override
  void readData() => print('Reading CSV file');

  @override
  void processData() => print('Parsing CSV rows');
}

class JsonProcessor extends DataProcessor {
  @override
  void readData() => print('Reading JSON file');

  @override
  void processData() => print('Parsing JSON objects');

  @override
  void saveData() => print('Saved to cloud storage');
}

Die Template-Methode steuert die Reihenfolge des Workflows. Unterklassen passen einzelne Schritte an, indem sie abstrakte Methoden implementieren und optional Standardimplementierungen überschreiben. Die Struktur des Algorithmus bleibt über alle Implementierungen hinweg konsistent.

Probier es selbst

import 'report_generator.dart';

void main() {
  // TODO: Erstelle einen SalesReport und rufe seine generate()-Methode auf

  // TODO: Drucke eine Leerzeile zur Trennung

  // TODO: Erstelle einen InventoryReport und rufe seine generate()-Methode auf
}
quiz iconTeste dich selbst

Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.

Alle Lektionen in Objektorientierte Programmierung