ストラテジービルダーまたはコンポジット+ストラテジーコンバイン

みなさんこんにちは!



今日は、2つの広範なデザインパターンStrategyCompositeの相互作用の結果を示したいと思います。その結果、いわゆる「Strategy Composer」が得られます。



問題



共同アプリケーションの戦略を構築するためのメカニズムを作成する必要があります。 人生では、たとえば、いくつかのイベントが発生したとき、アクションを実行するとき、イベントは次のような場合に使用できます:ユーザーが登録されている、ユーザーが生年月日を記入している、ユーザーがパスポートデータを入力していない-そのような一連のイベントの一致の結果として、たとえば、アンケートの適切なフィールドに入力するよう要求するメールをユーザーに送信します。 このようなチェックは、たとえば非同期で実行できます。



この目標を達成するために、StrategyおよびCompositeパターンの実装と互換性があります。



戦略パターン目標



ウィキペディアから: 要求しているクライアントのタイプまたは処理中のデータに応じて、適用するアルゴリズムを選択します。



複合パターンの目的



ウィキペディアから: このパターンは、プリミティブオブジェクトと複雑なオブジェクトを同時に構成できるクラスの階層を定義し、クライアントアーキテクチャを簡素化し、新しいタイプのオブジェクトを追加するプロセスを容易にします。



実装をすぐに見たい人のために: GitHubソース



最初に、リンカーを呼び出す方法を決定します。

$composite = new \CompositeAndStrategy\CompositeStrategy( new \CompositeAndStrategy\CompositeStrategyAnd( new \CompositeAndStrategy\CompositeStrategyOr( new \CompositeAndStrategy\StrategyFirst(), new \CompositeAndStrategy\StrategySecond() ), new \CompositeAndStrategy\StrategyThird() ), new \CompositeAndStrategy\CompositeStrategyOr( new \CompositeAndStrategy\StrategyFourth(), new \CompositeAndStrategy\StrategyFifth() ) ); $result = $composite->perform();
      
      







その結果、正常に完了した戦略を取得する必要があります。 単一のオブジェクトまたはオブジェクトのコレクションのいずれかです。 (この例では、2つの主要な複雑な戦略が見られます)



戦略とリンカーのインターフェイス(この場合、リンカー自体が戦略であるため):

 namespace CompositeAndStrategy; interface IStrategy { function perform(); }
      
      







リンカーインターフェイス(必須):

 namespace CompositeAndStrategy; interface ICompositeStrategy { function getAll(); function add(IStrategy $strategy); }
      
      







基本的なリンカーを書きましょう:

 namespace CompositeAndStrategy; class CompositeStrategy implements ICompositeStrategy, IStrategy { public function __construct() { $strategies = func_get_args(); if ($strategies) { foreach($strategies as $strategy) { if ($strategy instanceof IStrategy) { $this->add($strategy); } } } } /** * @var IStrategy[] */ protected $collection; /** * @param IStrategy $strategy */ public function add(IStrategy $strategy) { $this->collection[] = $strategy; } /** * @return IStrategy[] */ public function getAll() { return $this->collection; } /** * @return IStrategy */ public function perform() { foreach($this->getAll() as $strategy) { if ($strategy->perform()) { return $strategy; } } } }
      
      





私たちの主な関心事は、perform()メソッドです。 この場合、リンカ内のすべての要素を実行し、実行された最初の戦略を返します。



次に、上記で実装したリンカー基本クラスを拡張します。 リンカ戦略を実装します。リンカ戦略は、その戦略がすべて実行された場合に完了したと見なされます(論理演算「AND」)。

 namespace CompositeAndStrategy; class CompositeStrategyAnd extends CompositeStrategy { /** * @return bool|CompositeStrategyAnd */ public function perform() { foreach($this->getAll() as $strategy) { if (!$strategy->perform()) { return false; } } return $this; } }
      
      





次に、類推により、リンカ戦略を実装します。リンカ戦略は、少なくとも1つの戦略が実行された場合に完了すると見なされます(論理演算 "OR")。

 namespace CompositeAndStrategy; class CompositeStrategyOr extends CompositeStrategy { /** * @return CompositeStrategyOr */ public function perform() { foreach($this->getAll() as $strategy) { if ($strategy->perform()) { return $this; } } } }
      
      







戦略を実装することは私たちに残っています:



最初とメイン:

 namespace CompositeAndStrategy; class StrategyFirst implements IStrategy { /** * @param $bool * @return mixed */ protected function drawLog($bool) { echo get_called_class().' - ' . (int)$bool.'<hr />'; return $bool; } /** * @return bool|StrategyFirst */ public function perform() { if ($operation = $this->drawLog(rand(0, 1))) { return $this; } return false; } }
      
      







さらに4つの戦略:

 namespace CompositeAndStrategy; class StrategySecond extends StrategyFirst { }
      
      





 namespace CompositeAndStrategy; class StrategyThird extends StrategyFirst { }
      
      





 namespace CompositeAndStrategy; class StrategyFourth extends StrategyFirst { }
      
      





 namespace CompositeAndStrategy; class StrategyFifth extends StrategyFirst { }
      
      







もちろん実際には、戦略はより複雑になります。

同様の問題を解決するためのパターンがすでに存在することを除外しません。



コメントと批判は大歓迎です:)

良い週末を!



All Articles