はじめに
戦略パターンはアルゴリズムのファミリーを定義し、それらを相互に置き換えることができるように個別にカプセル化します。このモデルでは、アルゴリズムを使用する顧客とは独立してアルゴリズムを変更できます。
で構成されます。 抽象戦略ロール: Strategy クラス。通常はインターフェイスまたは抽象クラスによって実装されます。
具体的な戦略の役割: 関連するアルゴリズムと動作をパッケージ化します。
環境ロール: 最終的にクライアントによって呼び出される戦略クラスへの参照を保持します。
アプリケーション シナリオ
複数のクラスは、動作が異なるだけです。ストラテジ モードを使用して、実行時に実行される特定の動作を動的に選択できます。
異なる状況では異なる戦略 (アルゴリズム) を使用する必要があるか、将来的にその戦略が別の方法で実装される可能性があります。
特定の戦略 (アルゴリズム) の実装の詳細は顧客から隠されており、相互に完全に独立しています。
実装
手順
抽象ロールクラスを定義する(各実装の共通抽象メソッドを定義する)
具体的な戦略クラスを定義する(親クラスの共通メソッドを具体的に実装する)
環境ロールクラスを定義する(受信保存したインスタンスを取得して一律に実行します) Strategyクラスのインターフェースメソッド)
コード
<?php header('Content-Type:text/html;charset=utf-8'); /** * 策略模式演示代码 * * 为了更好地突出“策略”,我们这里以出行为例演示,日常出行大概分为以下几种工具:自驾车,公交车,地铁,火车,飞机,轮船 * * 下面一起看代码,领会何为策略模式 */ /** * Interface Travel 抽象策略角色 * 约定具体方法 */ interface Travel { public function go(); } /** * Class selfDriving 具体策略角色 * 自驾车 */ class bySelfDriving implements Travel { public function go() { echo '我自己开着车出去玩<br>'; } } /** * Class byBus具体策略角色 * 乘公交 */ class byBus implements Travel { public function go() { echo '我乘公交出去玩<br>'; } } /** * Class byMetro 具体策略角色 * 乘地铁 */ class byMetro implements Travel { public function go() { echo '我乘地铁出去玩<br>'; } } /** * Class byTrain 具体策略角色 * 乘火车 */ class byTrain implements Travel { public function go() { echo '我乘火车出去玩<br>'; } } /** * Class byAirplane 具体策略角色 * 乘飞机 */ class byAirplane implements Travel { public function go() { echo '我乘飞机出去玩<br>'; } } /** * Class bySteamship 具体策略角色 * 乘轮船 */ class bySteamship implements Travel { public function go() { echo '我乘轮船出去玩<br>'; } } /** * Class Mine 环境角色 */ class Mine{ private $_strategy; private $_isChange = false; /** * 构造方法 * 此处使用到了依赖注入和类型约束的概念,详情请参考 * 1.聊一聊PHP的依赖注入(DI) 和 控制反转(IoC) * @link https://segmentfault.com/a/1190000007209266 * 2.浅谈PHP的类型约束 * @link https://segmentfault.com/a/1190000007226476 * * @param Travel $travel */ public function __construct(Travel $travel) { $this->_strategy = $travel; } /** * 改变出行方式 * * @param Travel $travel */ public function change(Travel $travel) { $this->_strategy = $travel; $this->_isChange = true; } public function goTravel() { if ($this->_isChange) { echo '现在改变主意,'; $this->_strategy->go(); } else { $this->_strategy->go(); } } } /** * 客户端使用 */ $strategy = new Mine(new byBus()); // 乘公交 $strategy->goTravel(); // 乘地铁 $strategy->change(new byMetro()); $strategy->goTravel(); // 自驾车 $strategy->change(new bySelfDriving()); $strategy->goTravel(); // 其他根据具体应用选择实现
実行結果
遊びに行くためにバスに乗りました
気が変わって地下鉄に乗って遊びに行きました
さて気が変わって、一人で車で遊びに出かけました
長所と短所
長所
戦略パターンは、関連するアルゴリズムファミリーを管理する方法を提供します。ポリシー クラスの階層は、アルゴリズムまたは動作のファミリーを定義します。継承を適切に使用すると、共通のコードを親クラスに転送できるため、コードの重複を回避できます。
戦略パターンは、継承関係を置き換える方法を提供します。継承は複数のアルゴリズムまたは動作を処理できます。戦略パターンを使用していない場合、アルゴリズムまたは動作を使用する環境クラスにはいくつかのサブクラスがあり、各サブクラスが異なるアルゴリズムまたは動作を提供する可能性があります。ただし、この方法では、アルゴリズムまたは動作のユーザーがアルゴリズムまたは動作自体と混同されます。どのアルゴリズムを使用するか、またはどの動作を実行するかを決定するロジックが、アルゴリズムや動作のロジックと混合され、独立して進化することができなくなります。継承により、アルゴリズムや動作を動的に変更することができなくなります。
戦略パターンを使用すると、複数の条件付き転送ステートメントの使用を回避できます。複数の転送ステートメントは保守が容易ではありません。どのアルゴリズムまたは動作を採用するかのロジックを 1 つの複数の転送ステートメントにまとめてリストします。これは継承方法よりも原始的で後進的です。 。
欠点
クライアントはすべてのポリシー クラスを理解し、どれを使用するかを決定する必要があります。これは、適切なタイミングで適切なアルゴリズム クラスを選択するために、クライアントがこれらのアルゴリズムの違いを理解する必要があることを意味します。言い換えれば、戦略パターンは、クライアントがすべてのアルゴリズムまたは動作を知っている場合にのみ適しています。
戦略パターンは多くの戦略クラスを作成し、特定の戦略クラスごとに新しいクラスが生成されます。場合によっては、環境に依存する状態をクライアントに保存することで、ポリシー クラスを共有可能に設計できるため、ポリシー クラスのインスタンスをさまざまなクライアントで使用できるようになります。つまり、Flyweight パターンを使用してオブジェクトの数を減らすことができます。