身為軟體工程師,我們不斷地承擔著創建可維護、靈活和可擴展的系統的任務。在這種情況下,設計模式是強大的工具,可以幫助我們以結構化和可重複使用的方式解決重複出現的問題。其中一個設計模式是策略模式,它是行為模式家族的一部分。
策略模式可讓您定義一系列演算法,封裝每個演算法,並使它們可以互換。這意味著客戶端可以在運行時選擇合適的演算法或策略,而無需改變系統的核心功能。
在這篇部落格中,我將深入探討策略模式、其關鍵概念和組件、一個現實世界的範例,以及何時以及為何應該使用它。我們還將探索策略模式如何與抽象、枚舉甚至工廠模式一起工作,以使設計更加健壯和靈活。
策略模式是一種行為設計模式,可以在執行時選擇演算法的行為。策略模式不是採用單一的整體演算法,而是允許行為(或策略)可以互換,這使得系統更加靈活且更易於維護。
策略模式在以下情況下特別有用:
關注點分離:策略模式將演算法的關注點與系統的其餘部分分開。客戶端程式碼不知道演算法內部如何運作,使其更加模組化。
可擴充性:無需更改現有程式碼,只需新增策略類別即可新增演算法。
Wartbarkeit: Es reduziert die Komplexität des Codes, indem es unterschiedliche Verhaltensweisen an einzelne Strategieklassen delegiert, was die Wartung erleichtert.
Einfache Algorithmen: Wenn der Algorithmus, mit dem Sie arbeiten, unkompliziert ist und sich nicht ändert, kann die Verwendung eines Strategiemusters übertrieben sein.
Zu viele Strategien: Wenn Sie über eine große Anzahl von Strategien verfügen, kann dies zu einer Explosion von Klassen führen, was die Lesbarkeit beeinträchtigen und die Komplexität erhöhen kann.
Seltene Änderungen: Wenn sich der Algorithmus nicht oft ändert, kann die Einführung des Strategiemusters zu unnötiger Komplexität führen.
Das Strategiemuster besteht aus den folgenden Schlüsselkomponenten:
Kontext:
Strategie:
Konkrete Strategie:
Betrachten wir ein Zahlungsabwicklungssystem, das es Benutzern ermöglicht, mit verschiedenen Methoden wie Kreditkarte, PayPal und Kryptowährung zu bezahlen. Das Verhalten bei der Verarbeitung von Zahlungen unterscheidet sich für jede Methode, aber der Kontext (in diesem Fall der Einkaufswagen) muss in der Lage sein, Zahlungen zu verarbeiten, ohne sich um die Besonderheiten der einzelnen Zahlungsmethoden kümmern zu müssen.
Wir beginnen mit der Verwendung einer Enumeration, um verschiedene Zahlungsmethoden zu definieren. Dadurch wird die Auswahl der Zahlungsmethode typsicher und einfacher zu verwalten.
public enum PaymentMethod { CREDIT_CARD, PAYPAL, CRYPTOCURRENCY; }
Diese Klasse kapselt die Details, die zur Verarbeitung einer Zahlung erforderlich sind. Es enthält die Zahlungsmethode und die Zahlungsdetails (wie Kartennummer, E-Mail oder Kryptowährungsadresse).
public class PaymentInformation { private PaymentMethod paymentMethod; private String paymentDetails; public PaymentInformation(PaymentMethod paymentMethod, String paymentDetails) { this.paymentMethod = paymentMethod; this.paymentDetails = paymentDetails; } public PaymentMethod getPaymentMethod() { return paymentMethod; } public String getPaymentDetails() { return paymentDetails; } }
Dies wird die Basisschnittstelle für alle Zahlungsstrategien sein. Es definiert die gemeinsame Methode pay(), die alle konkreten Strategien implementieren.
public abstract class PaymentStrategy { protected PaymentInformation paymentInformation; public PaymentStrategy(PaymentInformation paymentInformation) { this.paymentInformation = paymentInformation; } public abstract void pay(double amount); protected boolean validatePaymentDetails() { return paymentInformation != null && paymentInformation.getPaymentDetails() != null && !paymentInformation.getPaymentDetails().isEmpty(); } }
Here, we implement the concrete strategies for CreditCardPayment, PayPalPayment, and CryptoPayment. Each of these classes implements the pay() method according to the payment type.
public class CreditCardPayment extends PaymentStrategy { public CreditCardPayment(PaymentInformation paymentInformation) { super(paymentInformation); } @Override public void pay(double amount) { if (validatePaymentDetails()) { System.out.println("Paid " + amount + " using Credit Card: " + paymentInformation.getPaymentDetails()); } else { System.out.println("Invalid Credit Card details."); } } }
public class PayPalPayment extends PaymentStrategy { public PayPalPayment(PaymentInformation paymentInformation) { super(paymentInformation); } @Override public void pay(double amount) { if (validatePaymentDetails()) { System.out.println("Paid " + amount + " using PayPal: " + paymentInformation.getPaymentDetails()); } else { System.out.println("Invalid PayPal details."); } } }
public class CryptoPayment extends PaymentStrategy { public CryptoPayment(PaymentInformation paymentInformation) { super(paymentInformation); } @Override public void pay(double amount) { if (validatePaymentDetails()) { System.out.println("Paid " + amount + " using Cryptocurrency to address: " + paymentInformation.getPaymentDetails()); } else { System.out.println("Invalid cryptocurrency address."); } } }
We will use the Factory Pattern to instantiate the appropriate payment strategy based on the payment method. This makes the system more flexible and allows the client to select a payment method at runtime.
public class PaymentStrategyFactory { public static PaymentStrategy createPaymentStrategy(PaymentInformation paymentInformation) { switch (paymentInformation.getPaymentMethod()) { case CREDIT_CARD: return new CreditCardPayment(paymentInformation); case PAYPAL: return new PayPalPayment(paymentInformation); case CRYPTOCURRENCY: return new CryptoPayment(paymentInformation); default: throw new IllegalArgumentException("Unsupported payment method: " + paymentInformation.getPaymentMethod()); } } }
The ShoppingCart class is the context where the payment strategy is used. It delegates the payment responsibility to the strategy selected by the factory.
public class ShoppingCart { private PaymentStrategy paymentStrategy; public ShoppingCart(PaymentInformation paymentInformation) { this.paymentStrategy = PaymentStrategyFactory.createPaymentStrategy(paymentInformation); } public void checkout(double amount) { paymentStrategy.pay(amount); } public void setPaymentInformation(PaymentInformation paymentInformation) { this.paymentStrategy = PaymentStrategyFactory.createPaymentStrategy(paymentInformation); } }
public class Main { public static void main(String[] args) { PaymentInformation cardInfo = new PaymentInformation(PaymentMethod.CREDIT_CARD, "1234-5678-9876"); ShoppingCart cart = new ShoppingCart(cardInfo); cart.checkout(250.0); PaymentInformation paypalInfo = new PaymentInformation(PaymentMethod.PAYPAL, "john.doe@example.com"); cart.setPaymentInformation(paypalInfo); cart.checkout(150.0); PaymentInformation cryptoInfo = new PaymentInformation(PaymentMethod.CRYPTOCURRENCY, "1A2B3C4D5E6F"); cart.setPaymentInformation(cryptoInfo); cart.checkout(500.0); } }
Paid 250.0 using Credit Card: 1234-5678-9876 Paid 150.0 using PayPal: john.doe@example.com Paid 500.0 using Cryptocurrency to address: 1A2B3C4D5E6F
behavior changes without modifying the core logic.
Das Strategiemuster ist ein wesentliches Entwurfsmuster, um Flexibilität und Modularität in Ihrem System zu erreichen. Es bietet eine elegante Möglichkeit, Algorithmen zu kapseln und ermöglicht Laufzeitflexibilität, ohne vorhandenen Code zu ändern. Egal, ob Sie ein Zahlungsverarbeitungssystem, eine Sortieralgorithmus-Bibliothek oder sogar eine Gaming-KI-Engine erstellen, das Strategiemuster kann dazu beitragen, dass Ihr Code wartbarer, erweiterbarer und einfacher zu ändern ist, wenn sich die Anforderungen ändern.
Durch die Nutzung von Abstraktion, Aufzählungen und dem Factory-Muster können Sie noch robustere Systeme erstellen, die sowohl typsicher als auch flexibel sind.
The above is the detailed content of Mastering the Strategy Design Pattern: A Guide for Developers. For more information, please follow other related articles on the PHP Chinese website!