Strategy-Pattern
Teil des Abschnitts Objektorientierte Programmierung der Java-Journey von Coddy — Lektion 69 von 87.
Das Strategy-Pattern ist ein Verhaltensmuster, das es Ihnen ermöglicht, eine Familie von Algorithmen zu definieren, jeden einzelnen in einer eigenen Klasse zu kapseln und sie austauschbar zu machen. Anstatt ein bestimmtes Verhalten fest zu codieren, können Sie Algorithmen zur Laufzeit austauschen, ohne den Code zu ändern, der sie verwendet.
Stellen Sie sich ein Zahlungssystem vor, das mehrere Zahlungsmethoden unterstützt. Ohne das Strategy-Pattern würden Sie bei einer unübersichtlichen bedingten Logik landen. Mit diesem Pattern wird jede Zahlungsmethode zu einer eigenen Strategie:
interface PaymentStrategy {
void pay(int amount);
}
class CreditCardPayment implements PaymentStrategy {
public void pay(int amount) {
System.out.println("Paid " + amount + " via Credit Card");
}
}
class PayPalPayment implements PaymentStrategy {
public void pay(int amount) {
System.out.println("Paid " + amount + " via PayPal");
}
}Die Context-Klasse hält eine Referenz auf eine Strategie und delegiert die Arbeit an diese. Der entscheidende Punkt ist, dass der Context nicht weiß, welche konkrete Strategie er verwendet – er kennt nur das Interface:
class ShoppingCart {
private PaymentStrategy paymentStrategy;
public void setPaymentStrategy(PaymentStrategy strategy) {
this.paymentStrategy = strategy;
}
public void checkout(int amount) {
paymentStrategy.pay(amount);
}
}Jetzt können Sie das Zahlungsverhalten dynamisch ändern:
ShoppingCart cart = new ShoppingCart();
cart.setPaymentStrategy(new CreditCardPayment());
cart.checkout(100); // 100 via Kreditkarte bezahlt
cart.setPaymentStrategy(new PayPalPayment());
cart.checkout(50); // 50 via PayPal bezahltDas Strategy-Pattern glänzt, wenn Sie mehrere Möglichkeiten haben, eine Aktion auszuführen, und einfach zwischen ihnen wechseln möchten. Das Hinzufügen einer neuen Zahlungsmethode bedeutet lediglich das Erstellen einer neuen Klasse, die PaymentStrategy implementiert – es sind keine Änderungen am bestehenden Code erforderlich.
Aufgabe
EinfachLassen Sie uns ein Textformatierungssystem mit dem Strategy Pattern bauen! Sie werden ein System erstellen, bei dem verschiedene Formatierungsstrategien zur Laufzeit ausgetauscht werden können, um Text auf verschiedene Arten zu transformieren – perfekt für eine Anwendung, die mehrere Ausgabeformate unterstützen muss.
Sie werden Ihren Code über vier Dateien organisieren:
TextFormatter.java: Definieren Sie dasTextFormatter-Interface, das alle Formatierungsstrategien implementieren werden. Es sollte eine einzige MethodeString format(String text)deklarieren, die einen String entgegennimmt und die formatierte Version zurückgibt.Formatters.java: Erstellen Sie drei konkrete Strategien, die IhrTextFormatter-Interface implementieren:UpperCaseFormatter- transformiert den Text in lauter Großbuchstaben.LowerCaseFormatter- transformiert den Text in lauter Kleinbuchstaben.TitleCaseFormatter- schreibt den ersten Buchstaben jedes Wortes groß, während der Rest klein geschrieben wird. Wörter sind durch Leerzeichen getrennt.TextEditor.java: Erstellen Sie die Kontextklasse, die eine Formatierungsstrategie verwendet. IhrTextEditorsollte Folgendes haben:Ein privates Feld, um die aktuelle
TextFormatter-Strategie zu halten.Eine
setFormatter(TextFormatter formatter)-Methode, die die aktive Formatierungsstrategie ändert.Eine
publishText(String text)-Methode, die den aktuellen Formatter auf den Text anwendet undPublished: [formatted text]ausgibt. Wenn kein Formatter gesetzt wurde, sollte siePublished: [original text]unverändert ausgeben.Main.java: Bringen Sie Ihr Strategiesystem zusammen! Sie erhalten zwei Eingaben: den zu formatierenden Text (String) und den Formatierungsstil (String:"upper","lower"oder"title").Erstellen Sie einen
TextEditorund rufen Sie zuerstpublishTextmit Ihrem Eingabetext auf, bevor Sie einen Formatter setzen (um das Standardverhalten zu demonstrieren).Setzen Sie dann basierend auf der Stileingabe die entsprechende Formatter-Strategie und rufen Sie
publishTexterneut mit demselben Text auf, um das formatierte Ergebnis anzuzeigen.
Sie erhalten nacheinander zwei Eingaben: den zu formatierenden Text (String) und den Formatierungsstil (String).
Zum Beispiel, bei den Eingaben hello world und title, wäre Ihre Ausgabe:
Published: hello world
Published: Hello WorldBeachten Sie, dass der TextEditor nichts über die spezifische Formatierungslogik weiß – er delegiert einfach an die Strategie, die gerade gesetzt ist. Dies macht es trivial, neue Formatierungsstile hinzuzufügen, ohne den Code des Editors anzupassen!
Spickzettel
Das Strategy Pattern (Strategiemuster) ist ein Verhaltensmuster, das eine Familie von Algorithmen definiert, jeden einzelnen in einer eigenen Klasse kapselt und sie austauschbar macht. Es ermöglicht den Austausch von Algorithmen zur Laufzeit, ohne den Code zu ändern, der sie verwendet.
Schlüsselkomponenten
Strategy Interface: Definiert die gemeinsame Schnittstelle für alle konkreten Strategien.
interface PaymentStrategy {
void pay(int amount);
}Konkrete Strategien: Implementieren das Strategy Interface mit spezifischen Algorithmen.
class CreditCardPayment implements PaymentStrategy {
public void pay(int amount) {
System.out.println("Paid " + amount + " via Credit Card");
}
}
class PayPalPayment implements PaymentStrategy {
public void pay(int amount) {
System.out.println("Paid " + amount + " via PayPal");
}
}Kontext-Klasse: Hält eine Referenz auf eine Strategie und delegiert die Arbeit an diese. Der Kontext kennt nur das Interface, nicht die konkrete Implementierung.
class ShoppingCart {
private PaymentStrategy paymentStrategy;
public void setPaymentStrategy(PaymentStrategy strategy) {
this.paymentStrategy = strategy;
}
public void checkout(int amount) {
paymentStrategy.pay(amount);
}
}Verwendung
Strategien können zur Laufzeit dynamisch geändert werden:
ShoppingCart cart = new ShoppingCart();
cart.setPaymentStrategy(new CreditCardPayment());
cart.checkout(100); // Paid 100 via Credit Card
cart.setPaymentStrategy(new PayPalPayment());
cart.checkout(50); // Paid 50 via PayPalVorteile
Das Strategy Pattern ist ideal, wenn Sie mehrere Möglichkeiten haben, eine Aktion auszuführen, und einfach zwischen ihnen wechseln möchten. Das Hinzufügen einer neuen Strategie bedeutet lediglich das Erstellen einer neuen Klasse, die das Strategy Interface implementiert – es sind keine Änderungen am bestehenden Code erforderlich.
Probier es selbst
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String text = scanner.nextLine();
String style = scanner.nextLine();
// TODO: Erstellen Sie eine TextEditor-Instanz
// TODO: Rufen Sie publishText mit dem Eingabetext auf (bevor ein Formatter gesetzt wird)
// TODO: Basierend auf der Style-Eingabe ("upper", "lower" oder "title"),
// setzen Sie den entsprechenden Formatter und rufen Sie publishText erneut auf
}
}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 DateienEinführung in die OOPKlassen vs. ObjekteDas this-SchlüsselwortMethodenFelder (Attribute)Konstruktor-MethodeKonstruktor-ÜberladungRückblick – Einfacher Taschenrechner4Vererbung
Grundlagen der Vererbung (extends)Das super-SchlüsselwortMethoden überschreiben (@Override)Konstruktor-VerkettungDie Object-KlasseEinfache & mehrstufige VererbungWarum keine Mehrfachvererbung von KlassenZusammenfassung - Mitarbeiter-Hierarchie7Spezielle Methoden & Object-Klasse
toString()-Methodeequals() und hashCode()clone()-MethodecompareTo() und ComparableComparator-InterfaceZusammenfassung – Benutzerdefiniertes Sortieren2Zugriffsmodifikatoren & Kapselung
Überblick über ZugriffsebenenGetter- und Setter-MethodenInformation HidingDas final-SchlüsselwortRückblick – Bankkonto-Manager5Polymorphismus
Grundlagen der MethodenüberladungMethodenüberschreibung (Laufzeit)Upcasting und DowncastingDer instanceof-OperatorAbstrakte Klassen und MethodenZusammenfassung – Formenrechner8Fortgeschrittene OOP-Konzepte
Komposition vs. VererbungAggregation vs. KompositionInnere, geschachtelte & anonyme KlassenEnums und Enum-MethodenRecords (Java 16+)Sealed Classes (Java 17+)11Design Patterns Teil 1
Einführung in Design PatternsSingleton-PatternFactory-PatternBuilder-PatternObserver-PatternStrategy-Pattern14Abschlussherausforderungen
E-Learning-PlattformBanksystemSpielcharakter-EntwicklungFahrzeugvermietung3Klasseneigenschaften & Statische Member
Instanz- vs. statische VariablenStatische MethodenStatische BlöckeKonstanten (static final)Zusammenfassung – Zähler & Utility6Interfaces & Abstrakte Klassen
Einführung in InterfacesInterfaces implementierenImplementierung mehrerer InterfacesDefault- & statische Methoden in InterfacesAbstrakte Klassen vs. InterfacesFunktionale InterfacesZusammenfassung - Zahlungssystem