ソフトウェア エンジニアとして、私たちは保守可能、柔軟性、拡張可能なシステムを作成するという使命を常に負っています。この文脈において、デザイン パターンは、繰り返し発生する問題を構造化された再利用可能な方法で解決するのに役立つ強力なツールです。そのようなデザイン パターンの 1 つが 戦略パターン です。これは 行動パターン ファミリーの一部です。
戦略パターンを使用すると、アルゴリズムのファミリーを定義し、それぞれをカプセル化し、それらを交換可能にすることができます。これは、クライアントがシステムのコア機能を変更することなく、実行時に適切なアルゴリズムまたは戦略を選択できることを意味します。
このブログでは、戦略パターン、その主要な概念とコンポーネント、実際の例、いつ、そしてなぜそれを使用する必要があるのかについて詳しく説明します。また、Strategy パターンが抽象化、列挙型、さらには Factory パターンと連携して設計をより堅牢かつ柔軟にする方法についても説明します。
戦略パターンは、アルゴリズムの動作を実行時に選択できるようにする動作設計パターンです。単一のモノリシックなアルゴリズムを持つ代わりに、戦略パターンを使用すると、動作 (または戦略) を交換できるようになり、システムがより柔軟になり、保守が容易になります。
戦略パターンは、次の場合に特に役立ちます。
懸念事項の分離: 戦略パターンは、アルゴリズムの懸念事項をシステムの残りの部分から分離します。クライアント コードはアルゴリズムが内部でどのように動作するかを認識しないため、よりモジュール化されています。
拡張性: 新しい戦略クラスを追加するだけで、既存のコードを変更せずに新しいアルゴリズムを追加できます。
保守性: さまざまな動作を個々の戦略クラスに委任することでコードの複雑さが軽減され、保守が容易になります。
単純なアルゴリズム: 使用しているアルゴリズムが単純で変化しない場合、戦略パターンの使用は過剰になる可能性があります。
戦略が多すぎます: 戦略の数が多いと、クラスの爆発的な増加につながる可能性があり、可読性が損なわれ、複雑さが増す可能性があります。
頻繁に変更されない: アルゴリズムが頻繁に変更されない場合、戦略パターンを導入すると不必要な複雑さが生じる可能性があります。
戦略パターンは次の主要なコンポーネントで構成されます:
コンテキスト:
戦略:
具体的な戦略:
ユーザーが クレジット カード、PayPal、暗号通貨 などのさまざまな方法を使用して支払うことができる支払い処理システムを考えてみましょう。支払いの処理方法の動作はメソッドごとに異なりますが、コンテキスト (この場合は ShoppingCart) は、各支払い方法の詳細を気にせずに支払いを処理できる必要があります。
まず、列挙型を使用してさまざまな支払い方法を定義します。これにより、支払い方法の選択がタイプセーフになり、管理が容易になります。
public enum PaymentMethod { CREDIT_CARD, PAYPAL, CRYPTOCURRENCY; }
このクラスは、支払いの処理に必要な詳細をカプセル化します。これには、支払い方法と支払いの詳細 (カード番号、電子メール、暗号通貨アドレスなど) が含まれます。
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; } }
これは、すべての支払い戦略の基本インターフェイスになります。これは、すべての具体的な戦略が実装する共通メソッド pay() を定義します。
public enum PaymentMethod { CREDIT_CARD, PAYPAL, CRYPTOCURRENCY; }
ここでは、CreditCardPayment、PayPalPayment、および CryptoPayment の具体的な戦略を実装します。これらの各クラスは、支払いタイプに応じて pay() メソッドを実装します。
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; } }
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(); } }
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."); } } }
ShoppingCart クラスは、支払い戦略が使用されるコンテキストです。支払い責任は工場が選択した戦略に委任されます。
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."); } } }
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()); } } }
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); } }
コアロジックを変更せずに動作が変わります。
戦略パターンは、システムの柔軟性とモジュール性を実現するために不可欠な設計パターンです。これは、アルゴリズムをカプセル化するエレガントな方法を提供し、既存のコードを変更することなく実行時の柔軟性を実現します。決済処理システム、並べ替えアルゴリズム ライブラリ、さらにはゲーム AI エンジンを構築している場合でも、戦略パターンは、要件の進化に応じてコードの保守性、拡張性、および変更を容易にするのに役立ちます。
抽象化、列挙型、およびファクトリ パターンを活用することで、タイプセーフで柔軟性のあるさらに堅牢なシステムを構築できます。
以上が戦略設計パターンをマスターする: 開発者向けガイドの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。