Menu
Coddy logo textTech

Template-Methoden-Muster

Teil des Abschnitts Objektorientierte Programmierung der GO-Journey von Coddy. Lektion 94 von 107.

Das Template-Method-Muster definiert das Grundgerüst eines Algorithmus in einem Basistyp und ermöglicht es Untertypen, bestimmte Schritte zu überschreiben, ohne die Gesamtstruktur zu ändern. Während der Decorator durch das Umschließen von Objekten Verhalten hinzufügt, steuert Template Method den Ablauf des Algorithmus und ermöglicht die Anpassung einzelner Schritte.

In Go implementieren wir dieses Muster, da es keine Vererbung gibt, mithilfe der Einbettung von Strukturen in Kombination mit Schnittstellen. Die „Template“-Struktur definiert die Algorithmusstruktur und ruft Methoden auf, die angepasst werden können:

type DataProcessor interface {
    ReadData() string
    ProcessData(data string) string
    SaveData(result string) string
}

type BaseProcessor struct {
    Impl DataProcessor
}

func (b *BaseProcessor) Execute() string {
    data := b.Impl.ReadData()
    result := b.Impl.ProcessData(data)
    return b.Impl.SaveData(result)
}

Konkrete Implementierungen liefern ihre eigenen Versionen jedes Schritts, während der Ablauf des Algorithmus unverändert bleibt:

type CSVProcessor struct{}

func (c CSVProcessor) ReadData() string       { return "csv-data" }
func (c CSVProcessor) ProcessData(d string) string { return "processed-" + d }
func (c CSVProcessor) SaveData(r string) string    { return "Saved: " + r }

type JSONProcessor struct{}

func (j JSONProcessor) ReadData() string       { return "json-data" }
func (j JSONProcessor) ProcessData(d string) string { return "parsed-" + d }
func (j JSONProcessor) SaveData(r string) string    { return "Stored: " + r }

Die Template-Methode Execute orchestriert die Schritte in einer festen Reihenfolge:

csvProc := &BaseProcessor{Impl: CSVProcessor{}}
fmt.Println(csvProc.Execute())  // Gespeichert: processed-csv-data

jsonProc := &BaseProcessor{Impl: JSONProcessor{}}
fmt.Println(jsonProc.Execute()) // Gespeichert: parsed-json-data

Die Template Method ist ideal, wenn du Algorithmen hast, die dieselbe Struktur aufweisen, sich aber in bestimmten Schritten unterscheiden, etwa Datenimport-/export-Pipelines, Berichtsgeneratoren oder Test-Frameworks.

challenge icon

Aufgabe

Einfach

Bauen wir ein System zur Berichtserstellung mit dem Template-Method-Muster! Du erstellst ein Framework, in dem verschiedene Berichtstypen denselben Erstellungsprozess befolgen, Daten sammeln, sie formatieren und das Ergebnis ausgeben, wobei jeder Berichtstyp diese Schritte jedoch unterschiedlich anpasst.

Du organisierst deinen Code über drei Dateien:

  • report.go: Definiere dein Interface und den Basisprozessor, der den Algorithmus zur Berichtserstellung koordiniert.

    Erstelle ein ReportGenerator-Interface mit drei Methoden, die die Schritte der Berichtserstellung darstellen:

    • GatherData() string: ruft die Rohdaten für den Bericht ab
    • FormatData(data string) string: wandelt die Daten in das Berichtsformat um
    • OutputReport(formatted string) string: erzeugt die abschließende Ausgabemeldung

    Erstelle eine ReportProcessor-Struktur, die eine ReportGenerator-Implementierung enthält. Füge eine Generate() string-Methode hinzu, die die drei Schritte in dieser Reihenfolge ausführt: sammeln, formatieren und anschließend ausgeben, wobei sie das Endergebnis zurückgibt.

  • generators.go: Implementiere konkrete Berichtsgeneratoren, die jeden Schritt anpassen.

    Erstelle zwei Berichtstypen:

    • SalesReport mit einem Region-Feld (string)
      • GatherData() gibt sales-data-[region] zurück
      • FormatData(data) gibt SALES REPORT: [data] zurück
      • OutputReport(formatted) gibt Printed: [formatted] zurück
    • InventoryReport mit einem Warehouse-Feld (string)
      • GatherData() gibt inventory-[warehouse] zurück
      • FormatData(data) gibt *** [data] *** zurück
      • OutputReport(formatted) gibt Exported: [formatted] zurück
  • main.go: Zeige, wie dieselbe Algorithmusstruktur abhängig von der Implementierung unterschiedliche Ergebnisse erzeugt.

    Lies den Berichtstyp (sales oder inventory) und den Konfigurationswert (Region für sales, Lager für inventory) ein. Erstelle den passenden Generator, verpacke ihn in einen ReportProcessor, rufe Generate() auf und gib das Ergebnis aus.

Die folgenden Eingaben werden bereitgestellt:

  • Zeile 1: Berichtstyp (sales oder inventory)
  • Zeile 2: Konfigurationswert (Regionsname oder Lagername)

Zum Beispiel bei:

sales
North

Deine Ausgabe sollte sein:

Printed: SALES REPORT: sales-data-North

Und bei:

inventory
MainHub

Deine Ausgabe sollte sein:

Exported: *** inventory-MainHub ***

Und bei:

sales
West

Deine Ausgabe sollte sein:

Printed: SALES REPORT: sales-data-West

Beachte, wie der ReportProcessor immer dieselben drei Schritte in derselben Reihenfolge aufruft, aber jeder Berichtstyp seine eigene Implementierung dieser Schritte bereitstellt. Das Gerüst des Algorithmus bleibt unverändert, während die Details variieren: Das ist das Template-Method-Muster in Aktion!

Probier es selbst

package main

import (
	"bufio"
	"fmt"
	"os"
)

func main() {
	scanner := bufio.NewScanner(os.Stdin)
	
	// Berichtstyp lesen
	scanner.Scan()
	reportType := scanner.Text()
	
	// Konfigurationswert lesen (Region oder Lager)
	scanner.Scan()
	configValue := scanner.Text()

	// TODO: Erstelle den entsprechenden Generator basierend auf reportType
	// - Wenn reportType "sales" ist, erstelle einen SalesReport mit Region gesetzt auf configValue
	// - Wenn reportType "inventory" ist, erstelle einen InventoryReport mit Warehouse gesetzt auf configValue
	
	// TODO: Erstelle einen ReportProcessor mit dem Generator
	
	// TODO: Rufe Generate() auf und gib das Ergebnis aus
	_ = reportType
	_ = configValue
	fmt.Println("TODO: Generate and print the report")
}
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

Übe selbstständig: Online-Go-Compiler