Menu
Coddy logo textTech

Strategie-Muster

Teil des Abschnitts Objektorientierte Programmierung der C++-Journey von Coddy. Lektion 95 von 104.

Das Strategy-Muster definiert eine Familie von Algorithmen, kapselt jeden einzelnen und macht sie austauschbar. Dadurch kannst du das Verhalten eines Objekts zur Laufzeit ändern, ohne seinen Code zu modifizieren – der Algorithmus variiert unabhängig von den Clients, die ihn verwenden.

Das Muster besteht aus drei Teilen: einer Strategy-Schnittstelle, die die Algorithmusmethode deklariert, konkreten Strategien, die verschiedene Varianten implementieren, und einem Kontext, der eine Strategie verwendet:

#include <iostream>
#include <memory>

// Strategy-Schnittstelle
class PaymentStrategy {
public:
    virtual void pay(int amount) = 0;
    virtual ~PaymentStrategy() = default;
};

// Konkrete Strategien
class CreditCardPayment : public PaymentStrategy {
public:
    void pay(int amount) override {
        std::cout << "Paid " << amount << " via Credit Card\n";
    }
};

class PayPalPayment : public PaymentStrategy {
public:
    void pay(int amount) override {
        std::cout << "Paid " << amount << " via PayPal\n";
    }
};

// Kontext
class ShoppingCart {
    std::unique_ptr<PaymentStrategy> strategy;
public:
    void setPaymentMethod(std::unique_ptr<PaymentStrategy> s) {
        strategy = std::move(s);
    }
    
    void checkout(int total) {
        if (strategy) strategy->pay(total);
    }
};

int main() {
    ShoppingCart cart;
    
    cart.setPaymentMethod(std::make_unique<CreditCardPayment>());
    cart.checkout(100);
    
    cart.setPaymentMethod(std::make_unique<PayPalPayment>());
    cart.checkout(50);
}

Der ShoppingCart weiß nicht, welche Zahlungsmethode er verwendet – er ruft einfach pay() für die jeweils festgelegte Strategie auf. Du kannst Strategien zur Laufzeit mit setPaymentMethod() austauschen, wodurch das System flexibel und einfach um neue Zahlungsoptionen erweiterbar wird.

Verwende Strategy, wenn du mehrere Algorithmen für eine bestimmte Aufgabe hast und dynamisch zwischen ihnen wechseln möchtest oder wenn du bedingte Anweisungen zur Auswahl des Verhaltens vermeiden möchtest.

challenge icon

Aufgabe

Einfach

Erstellen wir einen Versandkostenrechner, der das Strategy-Muster verwendet, um Lieferkosten anhand verschiedener Versandmethoden zu berechnen. Dies ist ein praktisches Szenario, in dem Algorithmen zur Laufzeit ausgetauscht werden müssen: Dasselbe Paket könnte auf dem Landweg, per Luftfracht oder als Expresssendung verschickt werden, wobei jede Methode ihre eigene Preislogik hat.

Du organisierst deinen Code auf drei Dateien verteilt:

  • ShippingStrategy.h: Definiere deine Strategie-Schnittstelle und konkrete Versandstrategien.

    Erstelle eine abstrakte Klasse ShippingStrategy mit einer rein virtuellen Methode calculateCost(double weight), die die Versandkosten als double zurückgibt, sowie einem virtuellen Destruktor.

    Implementiere anschließend drei konkrete Strategien:

    • GroundShipping: kostet 1.5 pro Gewichtseinheit (weight * 1.5)
    • AirShipping: kostet 4.0 pro Gewichtseinheit (weight * 4.0)
    • ExpressShipping: kostet 6.5 pro Gewichtseinheit plus eine Pauschale von 10.0 (weight * 6.5 + 10.0)
  • ShippingService.h: Erstelle die Kontextklasse, die eine Versandstrategie verwendet.

    Deine Klasse ShippingService sollte ein std::unique_ptr<ShippingStrategy> als privates Mitglied enthalten. Implementiere:

    • Eine Methode setStrategy(std::unique_ptr<ShippingStrategy> strategy), um die Versandmethode zu ändern
    • Eine Methode calculateShipping(double weight), die die aktuelle Strategie verwendet, um die Kosten zu berechnen und zurückzugeben

    Wenn beim Aufruf von calculateShipping keine Strategie festgelegt ist, gib 0.0 zurück.

  • main.cpp: Zeige das Umschalten von Strategien zur Laufzeit.

    Lies zwei Eingaben ein:

    1. Paketgewicht (double)
    2. Versandmethode: ground, air oder express

    Erstelle einen ShippingService und lege anhand der eingegebenen Methode die passende Strategie fest. Berechne die Versandkosten und gib sie aus.

    Wechsle anschließend zu einer anderen Strategie (verwende air, wenn die Eingabe nicht air war, andernfalls verwende ground) und berechne die Kosten für dasselbe Gewicht erneut. Dies demonstriert die Vorteile des Austauschs von Strategien zur Laufzeit.

    Gib jede Kostenangabe in einer eigenen Zeile mit genau einer Dezimalstelle aus, mit dem Namen der Methode als Präfix:

    [Method]: $[cost]

Zum Beispiel bei den Eingaben 5.0 und ground:

Ground: $7.5
Air: $20.0

Bei den Eingaben 3.0 und express:

Express: $29.5
Air: $12.0

Bei den Eingaben 10.0 und air:

Air: $40.0
Ground: $15.0

Beachte, dass ShippingService die Details der einzelnen Preisalgorithmen nicht kennen muss. Die Klasse delegiert einfach an die Strategie, die aktuell festgelegt ist. Du kannst problemlos neue Versandmethoden hinzufügen (zum Beispiel Drohnenlieferung oder Lieferung am selben Tag), ohne die Serviceklasse überhaupt zu ändern.

Probier es selbst

#include <iostream>
#include <string>
#include <iomanip>
#include <memory>
#include "ShippingStrategy.h"
#include "ShippingService.h"

int main() {
    double weight;
    std::string method;
    
    std::cin >> weight;
    std::cin >> method;
    
    // Setze die Ausgabe auf 1 Dezimalstelle
    std::cout << std::fixed << std::setprecision(1);
    
    ShippingService service;
    
    // TODO: Basierend auf der Eingabemethode ("ground", "air" oder "express"):
    // 1. Setze die passende Strategie auf dem Service
    // 2. Berechne und gib die Kosten im Format aus: "[Method]: $[cost]"
    
    // TODO: Wechsle zu einer anderen Strategie:
    // - Wenn die Eingabe "air" war, wechsle zu GroundShipping
    // - Andernfalls wechsle zu AirShipping
    // Berechne und gib die neuen Kosten aus
    
    return 0;
}
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-C++-Compiler