Menu
Coddy logo textTech

Strategy Pattern

Teil des Abschnitts Objektorientierte Programmierung der C#-Journey von Coddy — Lektion 55 von 70.

Das Strategy-Pattern ist ein Verhaltensmuster, mit dem Sie eine Familie von Algorithmen definieren, jeden in einer eigenen Klasse kapseln und sie zur Laufzeit austauschbar machen können. Anstatt das Verhalten fest zu codieren, injizieren Sie die gewünschte Strategie in ein Objekt.

Das Muster besteht aus drei Teilen: einer Strategie-Schnittstelle, die den Algorithmus-Vertrag definiert, konkreten Strategie-Klassen, die verschiedene Verhaltensweisen implementieren, und einer Kontext-Klasse, die eine Strategie verwendet:

public interface IPaymentStrategy
{
    void Pay(decimal amount);
}

public class CreditCardPayment : IPaymentStrategy
{
    public void Pay(decimal amount) => 
        Console.WriteLine($"Paid {amount} via Credit Card");
}

public class PayPalPayment : IPaymentStrategy
{
    public void Pay(decimal amount) => 
        Console.WriteLine($"Paid {amount} via PayPal");
}

public class ShoppingCart
{
    private IPaymentStrategy _paymentStrategy;
    
    public void SetPaymentMethod(IPaymentStrategy strategy)
    {
        _paymentStrategy = strategy;
    }
    
    public void Checkout(decimal total)
    {
        _paymentStrategy.Pay(total);
    }
}

Der Kontext (ShoppingCart) weiß nicht, welche Zahlungsmethode er verwendet – er ruft lediglich Pay() für die jeweils bereitgestellte Strategie auf:

var cart = new ShoppingCart();

cart.SetPaymentMethod(new CreditCardPayment());
cart.Checkout(99.99m);  // 99.99 via Kreditkarte bezahlt

cart.SetPaymentMethod(new PayPalPayment());
cart.Checkout(49.99m);  // 49.99 via PayPal bezahlt

Das Strategy-Pattern eliminiert komplexe bedingte Logik. Das Hinzufügen einer neuen Zahlungsmethode bedeutet das Erstellen einer neuen Klasse, die IPaymentStrategy implementiert – es sind keine Änderungen in ShoppingCart erforderlich. Dies macht Ihren Code offen für Erweiterungen, aber geschlossen für Modifikationen.

challenge icon

Aufgabe

Einfach

Lassen Sie uns einen Versandkostenrechner mit dem Strategy-Pattern erstellen. Verschiedene Versandmethoden haben unterschiedliche Preisalgorithmen, und Ihr System sollte es ermöglichen, zur Laufzeit zwischen ihnen zu wechseln, ohne die Kernlogik der Auftragsverarbeitung zu ändern.

Sie werden Ihren Code in drei Dateien organisieren:

  • ShippingStrategy.cs: Definieren Sie ein IShippingStrategy-Interface im Namespace Shipping mit einer Methode CalculateCost(double weight), die ein double zurückgibt. Erstellen Sie dann drei konkrete Strategieklassen:
    • StandardShipping - berechnet die Kosten als weight * 1.5
    • ExpressShipping - berechnet die Kosten als weight * 3.0 + 5.0 (beinhaltet eine pauschale Expressgebühr)
    • OvernightShipping - berechnet die Kosten als weight * 5.0 + 10.0 (Premium-Service mit höherer Grundgebühr)
  • OrderProcessor.cs: Erstellen Sie eine Klasse OrderProcessor im selben Namespace. Dies ist Ihre Kontextklasse, die eine Versandstrategie verwendet. Sie sollte Folgendes enthalten:
    • Ein privates Feld, um die aktuelle IShippingStrategy zu speichern
    • Eine Methode SetShippingMethod(IShippingStrategy strategy), um die Versandstrategie zu ändern
    • Eine Methode ProcessOrder(double weight), die die aktuelle Strategie verwendet, um die Versandkosten zu berechnen und zurückzugeben
  • Program.cs: Führen Sie alles zusammen, indem Sie einen OrderProcessor erstellen und demonstrieren, wie Sie Versandstrategien zur Laufzeit austauschen können. Derselbe Prozessor kann Kosten mit verschiedenen Algorithmen berechnen, indem er einfach seine Strategie ändert.

Sie erhalten zwei Eingaben:

  • Den Typ der Versandmethode: standard, express oder overnight
  • Das Paketgewicht als Dezimalzahl (z. B. 4.5)

Erstellen Sie einen OrderProcessor, legen Sie die entsprechende Versandstrategie basierend auf dem Eingabetyp fest, verarbeiten Sie dann die Bestellung und geben Sie die berechneten Kosten aus.

Wenn die Eingaben beispielsweise express und 4.5 sind, sollte die Ausgabe wie folgt lauten:

18.5

Dies demonstriert die Stärke des Strategy-Patterns – Ihr OrderProcessor enthält selbst keine Logik zur Versandberechnung. Er delegiert einfach an die jeweils zugewiesene Strategie, was es einfach macht, neue Versandmethoden (wie DroneDelivery) hinzuzufügen, ohne den Prozessor überhaupt modifizieren zu müssen!

Spickzettel

Das Strategy-Muster (Strategiemuster) ist ein Verhaltensmuster, das eine Familie von Algorithmen definiert, jeden einzelnen in einer eigenen Klasse kapselt und sie zur Laufzeit austauschbar macht.

Das Muster besteht aus drei Teilen:

  • Strategy-Interface: definiert den Algorithmus-Vertrag
  • Konkrete Strategie-Klassen: implementieren verschiedene Verhaltensweisen
  • Kontext-Klasse: verwendet eine Strategie, ohne deren Implementierungsdetails zu kennen

Beispielstruktur:

// Strategy-Interface
public interface IPaymentStrategy
{
    void Pay(decimal amount);
}

// Konkrete Strategien
public class CreditCardPayment : IPaymentStrategy
{
    public void Pay(decimal amount) => 
        Console.WriteLine($"Paid {amount} via Credit Card");
}

public class PayPalPayment : IPaymentStrategy
{
    public void Pay(decimal amount) => 
        Console.WriteLine($"Paid {amount} via PayPal");
}

// Kontext-Klasse
public class ShoppingCart
{
    private IPaymentStrategy _paymentStrategy;
    
    public void SetPaymentMethod(IPaymentStrategy strategy)
    {
        _paymentStrategy = strategy;
    }
    
    public void Checkout(decimal total)
    {
        _paymentStrategy.Pay(total);
    }
}

Verwendung - Wechseln der Strategien zur Laufzeit:

var cart = new ShoppingCart();

cart.SetPaymentMethod(new CreditCardPayment());
cart.Checkout(99.99m);  // Paid 99.99 via Credit Card

cart.SetPaymentMethod(new PayPalPayment());
cart.Checkout(49.99m);  // Paid 49.99 via PayPal

Vorteile:

  • Eliminiert komplexe bedingte Logik
  • Offen für Erweiterungen, geschlossen für Modifikationen (Open/Closed Principle)
  • Das Hinzufügen neuer Strategien erfordert nur das Erstellen neuer Klassen, keine Änderungen am bestehenden Code

Probier es selbst

using System;
using Shipping;

class Program
{
    public static void Main(string[] args)
    {
        // Eingabe lesen
        string shippingType = Console.ReadLine();
        double weight = Convert.ToDouble(Console.ReadLine());

        // TODO: Eine OrderProcessor-Instanz erstellen

        // TODO: Basierend auf shippingType ("standard", "express" oder "overnight"),
        // die entsprechende Versandstrategie erstellen und diese im Prozessor festlegen

        // TODO: Die Bestellung verarbeiten und die berechneten Kosten ausgeben
    }
}
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