Menu
Coddy logo textTech

Strategy-Muster

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

Das Strategie-Muster ermöglicht es dir, eine Familie von Algorithmen zu definieren, jeden einzelnen zu kapseln und sie zur Laufzeit austauschbar zu machen. Im Gegensatz zum Observer-Muster, bei dem mehrere Objekte auf ein Ereignis reagieren, kannst du mit Strategy ein einzelnes Objekt dynamisch zwischen verschiedenen Verhaltensweisen wechseln lassen.

In Go implementieren wir Strategy, indem wir ein Interface für den Algorithmus definieren und verschiedene Implementierungen in eine Kontextstruktur injizieren:

type PaymentStrategy interface {
    Pay(amount float64) string
}

type CreditCard struct{}
func (c CreditCard) Pay(amount float64) string {
    return fmt.Sprintf("Paid %.2f via Credit Card", amount)
}

type PayPal struct{}
func (p PayPal) Pay(amount float64) string {
    return fmt.Sprintf("Paid %.2f via PayPal", amount)
}

Die Kontextstruktur enthält eine Referenz auf die Strategieschnittstelle, sodass der Algorithmus ausgetauscht werden kann, ohne den Code des Kontexts zu ändern:

type Checkout struct {
    strategy PaymentStrategy
}

func (c *Checkout) SetStrategy(s PaymentStrategy) {
    c.strategy = s
}

func (c *Checkout) ProcessPayment(amount float64) string {
    return c.strategy.Pay(amount)
}

Jetzt kannst du die Zahlungsmethode zur Laufzeit ändern:

checkout := &Checkout{}

checkout.SetStrategy(CreditCard{})
fmt.Println(checkout.ProcessPayment(100.00))  // Bezahlt 100.00 via Kreditkarte

checkout.SetStrategy(PayPal{})
fmt.Println(checkout.ProcessPayment(50.00))   // Bezahlt 50.00 via PayPal

Strategy ist ideal, wenn du mehrere Möglichkeiten hast, eine Operation auszuführen, und anhand von Benutzereingaben, der Konfiguration oder Laufzeitbedingungen eine davon auswählen musst. Häufige Anwendungsfälle sind Sortieralgorithmen, Komprimierungsmethoden und Validierungsregeln.

challenge icon

Aufgabe

Einfach

Erstellen wir ein Textformatierungssystem mithilfe des Strategy-Musters! Du erstellst verschiedene Formatierungsstrategien, die zur Laufzeit ausgetauscht werden können, sodass derselbe Textprozessor unterschiedliche Ausgabestile erzeugen kann, ohne seinen Kerncode zu ändern.

Du organisierst deinen Code über drei Dateien:

  • formatter.go: Definiere deine Strategie-Schnittstelle und konkrete Formatierungsstrategien.

    Erstelle eine TextFormatter-Schnittstelle mit einer Methode Format(text string) string, die Text gemäß den Regeln der Strategie umwandelt.

    Implementiere drei Formatierungsstrategien:

    • UppercaseFormatter: wandelt den Text vollständig in Großbuchstaben um
    • SnakeCaseFormatter: wandelt Leerzeichen in Unterstriche um und schreibt den Text in Kleinbuchstaben
    • TitleFormatter: schreibt den ersten Buchstaben jedes Wortes groß (Wörter werden durch Leerzeichen getrennt)
  • processor.go: Erstelle deine Kontextstruktur, die die Formatierungsstrategie verwendet.

    Erstelle eine TextProcessor-Struktur, die eine TextFormatter-Strategie enthält. Füge diese Methoden hinzu:

    • SetFormatter(f TextFormatter), um die aktive Formatierungsstrategie zu ändern
    • Process(text string) string, die den aktuellen Formatierer auf den Text anwendet

    Erstelle außerdem einen NewTextProcessor()-Konstruktor, der einen Prozessor ohne anfänglich gesetzten Formatierer zurückgibt.

  • main.go: Zeige das Umschalten zwischen Strategien zur Laufzeit.

    Lies einen Text ein und anschließend die Anzahl der Formatierungsoperationen. Lies für jede Operation den Formattyp (upper, snake oder title) ein, setze den entsprechenden Formatierer für deinen Prozessor, verarbeite den ursprünglichen Text und gib das Ergebnis aus.

Die folgenden Eingaben werden bereitgestellt:

  • Zeile 1: Der zu formatierende Text
  • Zeile 2: Anzahl der Formatierungsoperationen
  • Folgende Zeilen: Formattyp für jede Operation

Zum Beispiel bei folgender Eingabe:

hello world today
3
upper
snake
title

Deine Ausgabe sollte folgendermaßen aussehen:

HELLO WORLD TODAY
hello_world_today
Hello World Today

Und bei folgender Eingabe:

Go Programming Language
2
snake
upper

Deine Ausgabe sollte folgendermaßen aussehen:

go_programming_language
GO PROGRAMMING LANGUAGE

Und bei folgender Eingabe:

design patterns are useful
1
title

Deine Ausgabe sollte folgendermaßen aussehen:

Design Patterns Are Useful

Beachte, wie derselbe TextProcessor völlig unterschiedliche Ausgaben erzeugt, indem einfach seine Formatierungsstrategie ausgetauscht wird. Der Prozessor weiß nicht, welcher konkrete Formatierer verwendet wird, und muss es auch nicht wissen. Er delegiert die Aufgabe einfach an die Strategie, die aktuell gesetzt ist!

Probier es selbst

package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

func main() {
	reader := bufio.NewReader(os.Stdin)
	
	// Lese den zu formatierenden Text
	text, _ := reader.ReadString('\n')
	text = strings.TrimSpace(text)
	
	// Lese die Anzahl der Operationen
	countStr, _ := reader.ReadString('\n')
	count, _ := strconv.Atoi(strings.TrimSpace(countStr))
	
	// Erstelle einen neuen Textprozessor
	processor := NewTextProcessor()
	
	// Verarbeite jede Formatierungsoperation
	for i := 0; i < count; i++ {
		formatType, _ := reader.ReadString('\n')
		formatType = strings.TrimSpace(formatType)
		
		// TODO: Basierend auf formatType ("upper", "snake" oder "title"),
		// setze den entsprechenden Formatter auf dem Prozessor
		// und gib den verarbeiteten Text aus
		
	}
}
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