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 bezahltDas 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.
Aufgabe
EinfachLassen 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 einIShippingStrategy-Interface im NamespaceShippingmit einer MethodeCalculateCost(double weight), die eindoublezurückgibt. Erstellen Sie dann drei konkrete Strategieklassen:StandardShipping- berechnet die Kosten alsweight * 1.5ExpressShipping- berechnet die Kosten alsweight * 3.0 + 5.0(beinhaltet eine pauschale Expressgebühr)OvernightShipping- berechnet die Kosten alsweight * 5.0 + 10.0(Premium-Service mit höherer Grundgebühr)
OrderProcessor.cs: Erstellen Sie eine KlasseOrderProcessorim selben Namespace. Dies ist Ihre Kontextklasse, die eine Versandstrategie verwendet. Sie sollte Folgendes enthalten:- Ein privates Feld, um die aktuelle
IShippingStrategyzu 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
- Ein privates Feld, um die aktuelle
Program.cs: Führen Sie alles zusammen, indem Sie einenOrderProcessorerstellen 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,expressoderovernight - 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.5Dies 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 PayPalVorteile:
- 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
}
}
Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Objektorientierte Programmierung
1Grundlagen der OOP
Externe DateienNamespaces & DirektivenEinführung in Klassen & ObjekteDas 'this'-SchlüsselwortMethoden und ParameterFelder vs. EigenschaftenKonstruktorenObjekt-InitialisiererZusammenfassung - Einfacher Taschenrechner4Vererbung
Grundlagen der Vererbung (:) SyntaxDas 'base'-SchlüsselwortVirtual & Override SchlüsselwörterVersiegelte KlassenDie 'object'-BasisklasseZusammenfassung – Mitarbeiter-Hierarchie7Fortgeschrittene Funktionen
OperatorüberladungIndexer (this[])ToString() überschreibenErweiterungsmethodenZusammenfassung - Benutzerdefinierte Liste10Design Patterns Teil 1
Einführung in Design PatternsThread-sicheres SingletonFactory PatternObserver Pattern (Events)Strategy Pattern2Eigenschaften & Statische Member
Automatisch implementierte EigenschaftenRead-Only- & Write-Only-EigenschaftenStatische Felder & MethodenStatische KlassenExpression-Bodied Member5Polymorphismus & Interfaces
Compile- vs. Runtime-PolymorphismusInterface vs. abstrakte KlasseMehrfache InterfacesExplizite InterfacesUpcasting & DowncastingRecap – Shape Calculator3Klassenarchitektur
Instanz- vs. statische Daten'readonly' & 'const' SchlüsselwörterBacking FieldsZusammenfassung - Bankkonto-Manager6Kapselung
ZugriffsmodifikatorenProperties zur KapselungImplementierung von Data HidingImmutability-MusterRückblick – Studierendendaten