「戦略パターン。 fun'aの簡単な「または私がインタビューに行く理由」PHP Juniorについて

あいさつ



みなさんこんにちは! この喜びに満ちた、かなり暖かい金曜日に、(より楽しいバージョンで引用するために)私に直接会った。 正直なところ、このアクションは非常に頻繁に発生しますが、通常どおり、感覚が原因です。
なんてバカなんだ
今回は少し違った感覚で訪れましたが、確信したように、私だけではありません。 この気持ちは、インタビューの1つを思い出しました。「デコレーター」パターンのスケルトンを書くように頼まれました。これは、インタビュアーの個人的な考え方が古典的な解釈とはまったく異なることが判明しました。



読者の脳を「認知的不協和音」に失望させないようにするために、この記事ではこの会社の 「仮説的」インタビューについて説明することを明確にします。したがって、「戦略」パターンについて話すように求められた場合 前のケースのように、私の回答はインタビュアーの目には少なくとも疑わしく見えたでしょう。



覗かないで


知識の電子倉庫には、C ++の例が記載された完全な記事「Strategy Design Template」があり、GoFの本と既知のすべてのプログラミング言語(そして突然、難解な言語を含む)から引用されていることがわかっているので、私の仕事は:同様の例を記事からパターンの概念に詰め込みます。 何をする必要があり、何が起こったのか見てみましょう。



見た、修羅、見た


私の意見では、特定の種類のクラスを操作するのは良くありません。この場合クラスインターフェースに関する知識だけでなく、多くの追加メソッド(多くの場合open === public )を通常含む実装についても知っています 。 代わりに、 インターフェイスベースのアプローチが提案されているため、例をリファクタリングする最初のステップはそれらを強調することです。



interface IValidator { /** * @param Mixed|stdClass $validatorParam * @return Boolean */ function isValid($validatorParam); }
      
      





少しリラックスできるようにしたので、コードには最小限のコメントが含まれます(実際、IDEのコードには最小限のコメントが含まれています)。 合計:渡された引数について有効性判定を発行できるエンティティ。 この場所で、あなたのように、それは私を歪め始めることを書く価値があります: しかし、私は息を吐き(空気だけ)、制限に耐えて、書き続けます。 パターンの名前に基づいて、さまざまなケース(またはユースケース)に異なる戦略を適用するためのメカニズム(または機会 )が必要です。たとえば、コンパイル段階だけでなく、外部要因にも依存します。 正式な形式では、私たちの欲求は次のようになります。



 function Validate(IValidator $validateStrategy, $param) { return $validateStrategy->isValid($param); }
      
      





そして、たとえば、ユーザー名は次のようになります。



 function ValidateName($userName) { return Validate(new NameValidator(), $userName); // obsolete $param, fixed by domage@habrahabr }
      
      





「同意します」あなたの目に見えない質問に、熱心な読者に答えます:
コンストラクターが呼び出されるたびに? シングルトンまたは静的関数変数はできませんか?
しかし、これらは次のリファクタリングの問題です。 例のサブジェクト領域に戻りましょう。検証用のエンティティ、たとえばメールボックス(電子メール)、および質問への回答が必要です。これはHohoのアドレスですか? この住所は短すぎませんか、長すぎませんか?



 class HohoEmailValidator implements IValidator { public function isValid(/*String*/ $email) { return $email === 'Hoho'; // best comparison of ever } } class LengthEmailValidator implements IValidator { public function isValid(/*String*/ $email) { return strlen($email) > 5; } } class LengthMaxEmailValidator implements IValidator { public function isValid(/*String*/ $email) { return strlen($email) <= 100500; } }
      
      





Validate()関数ではバリデータのコレクション(リスト、配列)を使用できないため、バリデータのコレクション(リスト、配列)を引数として使用して機能を拡張する必要があります。



 function IsValidByStrategy(/*Collection of IValidators*/ $strategyCollection, /*Any type*/ $param) { foreach($strategyCollection as $strategy) { if($strategy instanceof IValidator) { //       -_- if(!$strategy->isValid($param)) return false; } } return true; }
      
      





そうそう、これは頭の上の髪のいい動きです: すべてのカードを手に入れたので、渡された電子メールアドレスをチェックする戦略パターンのコンテキストで、あまり有用でない最初の関数を説明できます。



 //  true,  function IsValidEmailStrong($email = 'habr@habr.ru') { return IsValidByStrategy(array( new HohoEmailValidator(), //  ""  new LengthEmailValidator() //    5  ), $email); }
      
      





検証ロジックはスマートであることが判明しました(<-これはエラーではありません):

追加


サンプルをばかげたものにするために( LengthEmailValidatorを思い出してください )、 IsValidByStrategy()関数の動作の変更に関してstrtegyパターンをもう一度適用し、次の機能を実装します。
 interface IsValidReturnRule { /** * @param Boolean $validateResult * @param Boolean $validateResultByStep * @return Boolean */ function validateStep(&$validateResult, $validateResultByStep); /** * @return Boolean */ function initialize(); } class ValidReturnRuleAny implements IsValidReturnRule { public function validateStep(&$validateResult, $validateResultByStep) { $validateResult |= $validateResultByStep; return $validateResult; } public function initialize() { return false; } } function IsValidByStrategyByRetRule(/*Collection of IValidators*/ $strategyCollection, /*Any type*/ $param, IsValidReturnRule $retStrategy) { $result = $retStrategy->initialize(); foreach($strategyCollection as $strategy) { if($strategy instanceof IValidator) { if($retStrategy->validateStep($result, $strategy->isValid($param))) return $result; } } return $result; }
      
      





受け取った合計: 次に、郵送先住所が有効と見なされることを確認するために、次のコードを記述する必要があります。



 class ValidReturnRuleAny implements IsValidReturnRule { public function validateStep(&$validateResult, $validateResultByStep) { $validateResult |= $validateResultByStep; return $validateResult; } public function initialize() { return false; } } function IsValidEmailSoft($email = 'habr@habr.ru') { return IsValidByStrategyByRetRule(array( new HohoEmailValidator(), new LengthEmailValidator() ), $email, new ValidReturnRuleAny()); }
      
      





検証戦略の結果処理するための戦略の使用により、 IsValidEmailSoft関数は、長さが100500文字以下のアドレスを気にしません。

覚えておくべきこと


一般的なタスクの洗練されたソリューション(言語機能を含む)を実装する設計ソリューションには、使用上の制限があります。 この意味で、GoFのデザインパターンは美しく構成されています。



おわりに


この記事は、単純なことについて、「そんなに水を注ぐ」ことができる方法の例になるのではないかと心配しています。 しかし、1つ確かなことがあります。この記事の後に、何らかの理由でデザインパターンを熟知することを怠ったか、恐れていた私たちが恐怖を克服できたら素晴らしいことです。



結局のところ、知識は無知よりも優れており、光は闇よりも優れています。 ありがとう、素敵な週末を!



更新:

PSはい、これは私の最初の記事です。おめでとう、批判、,辱、間違い/間違いはPMで受け入れられます。



All Articles