Das Strategy Pattern ist ein Verhaltensmuster, das es einem Objekt ermöglicht, sein Verhalten zur Laufzeit zu ändern. Statt festen Code für bestimmte Verhaltensweisen zu verwenden, kapselt dieses Muster die Algorithmen in eigenständigen Klassen. Ein Objekt kann die Strategie dann dynamisch auswählen, was Flexibilität und Erweiterbarkeit ermöglicht.
Was ist das Strategy Pattern?
Das Strategy Pattern definiert eine Familie von Algorithmen, kapselt sie und macht sie austauschbar. Es ermöglicht einem Objekt, sein Verhalten basierend auf der aktuellen Strategie zu ändern, ohne den Code des Objekts zu ändern. Dieses Muster fördert die Entkopplung und lässt das System flexibler und erweiterbarer werden.
Komponenten des Strategy Patterns
- Context: Das Context-Objekt hält eine Referenz auf ein Strategy-Objekt. Es delegiert die Ausführung des Algorithmus an das Strategy-Objekt.
- Strategy: Die Strategy-Schnittstelle definiert die allgemeine Methode, die von allen konkreten Strategien implementiert wird.
- ConcreteStrategy: Diese Klassen implementieren die Strategy-Schnittstelle und definieren den spezifischen Algorithmus.
Beispiel des Strategy Patterns in C++
Im folgenden Beispiel wird das Strategy Pattern verwendet, um das Verhalten einer Zahlungsabwicklung zu modellieren. Je nach Zahlungsstrategie kann der Kunde zwischen verschiedenen Zahlungsmethoden wählen.
#include <iostream>
#include <memory>
// Strategy: Abstrakte Schnittstelle für die Zahlungsmethoden
class PaymentStrategy {
public:
virtual void pay(int amount) = 0;
virtual ~PaymentStrategy() = default;
};
// ConcreteStrategy: Zahlung per Kreditkarte
class CreditCardPayment : public PaymentStrategy {
public:
void pay(int amount) override {
std::cout << "Bezahlung von " << amount << " Euro mit Kreditkarte." << std::endl;
}
};
// ConcreteStrategy: Zahlung per PayPal
class PayPalPayment : public PaymentStrategy {
public:
void pay(int amount) override {
std::cout << "Bezahlung von " << amount << " Euro mit PayPal." << std::endl;
}
};
// ConcreteStrategy: Zahlung per Banküberweisung
class BankTransferPayment : public PaymentStrategy {
public:
void pay(int amount) override {
std::cout << "Bezahlung von " << amount << " Euro per Banküberweisung." << std::endl;
}
};
// Context: Der Kunde, der eine Zahlungsmethode auswählt
class Customer {
private:
std::shared_ptr<PaymentStrategy> paymentStrategy;
public:
void setPaymentStrategy(std::shared_ptr<PaymentStrategy> strategy) {
paymentStrategy = strategy;
}
void makePayment(int amount) {
paymentStrategy->pay(amount);
}
};
// Client-Code
int main() {
Customer customer;
// Kunde wählt Kreditkarte als Zahlungsmethode
customer.setPaymentStrategy(std::make_shared<CreditCardPayment>());
customer.makePayment(100);
// Kunde wählt PayPal als Zahlungsmethode
customer.setPaymentStrategy(std::make_shared<PayPalPayment>());
customer.makePayment(200);
// Kunde wählt Banküberweisung als Zahlungsmethode
customer.setPaymentStrategy(std::make_shared<BankTransferPayment>());
customer.makePayment(300);
return 0;
}
Erklärung des C++-Beispiels
- PaymentStrategy: Die abstrakte Klasse
PaymentStrategy
definiert die Methodepay()
, die von den konkreten Zahlungsstrategien implementiert wird. Sie ist die gemeinsame Schnittstelle für alle Strategien. - ConcreteStrategy: Die Klassen
CreditCardPayment
,PayPalPayment
undBankTransferPayment
sind konkrete Implementierungen derPaymentStrategy
. Jede dieser Klassen definiert die spezifische Art der Zahlung. - Customer: Das
Customer
-Objekt ist der Kontext. Es enthält eine Referenz auf das aktuellePaymentStrategy
-Objekt. Der Kunde kann die Zahlungsstrategie zur Laufzeit ändern und somit zwischen verschiedenen Zahlungsmethoden wählen. - Client: Der Client wählt die Zahlungsstrategie und fordert die Zahlung an. Je nach gewählter Strategie wird eine andere Zahlungsmethode ausgeführt.
Vorteile des Strategy Patterns
- Entkopplung: Das Strategy Pattern trennt die verschiedenen Algorithmen von der Kontextklasse. So bleibt der Code übersichtlich und flexibel.
- Erweiterbarkeit: Neue Strategien können einfach hinzugefügt werden, ohne den Kontext oder andere Strategien zu verändern.
- Verhalten zur Laufzeit ändern: Das Verhalten eines Objekts kann dynamisch geändert werden, ohne dass der Code geändert werden muss.
- Vermeidung von Bedingungen: Anstatt
if
– oderswitch
-Bedingungen im Code zu verwenden, delegiert das System das Verhalten an die Strategie.
Nachteile des Strategy Patterns
- Erhöhte Komplexität: Es entstehen viele zusätzliche Klassen, was den Code komplexer und schwerer nachvollziehbar machen kann.
- Verwendung von Schnittstellen: In einigen Fällen kann es unnötig erscheinen, ein Interface für einfache Aufgaben zu definieren.
- Zusätzlicher Overhead: Wenn nur wenige Strategien existieren, könnte der zusätzliche Overhead des Musters übertrieben wirken.
Fazit
Das Strategy Pattern ist ein mächtiges Designmuster, das die Flexibilität und Erweiterbarkeit von Software erhöht. Es ermöglicht einem Objekt, sein Verhalten zur Laufzeit zu ändern, indem es die Algorithmen in eigenständige Klassen auslagert. Das Beispiel mit der Zahlungsmethode zeigt, wie dieses Muster in der Praxis eingesetzt werden kann. Das Pattern eignet sich hervorragend, wenn ein Objekt unterschiedliche Varianten eines Verhaltens haben kann und es wichtig ist, diese zur Laufzeit auszuwählen.
Zurück zur Übersicht der Pattern: Liste der Design-Pattern