ソフトウェア開発では、さまざまな環境や条件に応じて、さまざまなアルゴリズムや戦略が使用されます。この機能を完了するには、さまざまなアルゴリズムまたは戦略を選択してください。検索や並べ替えなど、一般的なメソッドはクラス内でハードコーディングされます。複数の検索アルゴリズムを提供する必要がある場合は、これらのアルゴリズムをクラスに記述し、各メソッドが特定のクラスに対応するようにすることができます。検索アルゴリズム; もちろん、これらの検索アルゴリズムを統一メソッドでカプセル化し、if...else... や case などの条件文を通じて選択することもできます。これら 2 つの実装方法をハード コーディングと呼びます。新しい検索アルゴリズムを追加する必要がある場合は、カプセル化されたアルゴリズム クラスのソース コードを変更して、検索アルゴリズムを変更する必要があります。また、クライアントの呼び出しコードも変更する必要があります。このアルゴリズム クラスは、多数の検索アルゴリズムをカプセル化します。このタイプのコードはより複雑になり、保守が困難になります。これらの戦略をクライアント側に組み込む場合、選択できるアルゴリズムが多数ある場合、クライアント プログラムが大きくなり、保守が困難になるため、このアプローチはさらに望ましくありません。
アルゴリズムをオブジェクトから分離して、アルゴリズムを使用するクライアントとは独立してアルゴリズムを変更できるようにするにはどうすればよいでしょうか?この目的のために、戦略パターンを紹介します。
ストラテジー モードは、アルゴリズム クラスター モードとも呼ばれ、さまざまなアルゴリズム ファミリを定義し、アルゴリズムを使用する顧客に関係なくアルゴリズムを変更できます。
一般的な使用シナリオには、日付または ID に基づくオブジェクト フィルタリングが含まれます。たとえば、単体テストでは、ファイル ストレージとメモリ ストレージを切り替えることができます。
<?phpnamespace DesignPatterns\Behavioral\Strategy;/** * ObjectCollection类 */class ObjectCollection{ /** * @var array */ private $elements; /** * @var ComparatorInterface */ private $comparator; /** * @param array $elements */ public function __construct(array $elements = array()) { $this->elements = $elements; } /** * @return array */ public function sort() { if (!$this->comparator) { throw new \LogicException("Comparator is not set"); } $callback = array($this->comparator, 'compare'); uasort($this->elements, $callback); return $this->elements; } /** * @param ComparatorInterface $comparator * * @return void */ public function setComparator(ComparatorInterface $comparator) { $this->comparator = $comparator; }}
<?phpnamespace DesignPatterns\Behavioral\Strategy;/** * ComparatorInterface类 */interface ComparatorInterface{ /** * @param mixed $a * @param mixed $b * * @return bool */ public function compare($a, $b);}
<?phpnamespace DesignPatterns\Behavioral\Strategy;/** * DateComparator类 */class DateComparator implements ComparatorInterface{ /** * {@inheritdoc} */ public function compare($a, $b) { $aDate = new \DateTime($a['date']); $bDate = new \DateTime($b['date']); if ($aDate == $bDate) { return 0; } else { return $aDate < $bDate ? -1 : 1; } }}
<?phpnamespace DesignPatterns\Behavioral\Strategy;/** * IdComparator类 */class IdComparator implements ComparatorInterface{ /** * {@inheritdoc} */ public function compare($a, $b) { if ($a['id'] == $b['id']) { return 0; } else { return $a['id'] < $b['id'] ? -1 : 1; } }}
<?phpnamespace DesignPatterns\Behavioral\Strategy\Tests;use DesignPatterns\Behavioral\Strategy\DateComparator;use DesignPatterns\Behavioral\Strategy\IdComparator;use DesignPatterns\Behavioral\Strategy\ObjectCollection;use DesignPatterns\Behavioral\Strategy\Strategy;/** * 策略模式测试 */class StrategyTest extends \PHPUnit_Framework_TestCase{ public function getIdCollection() { return array( array( array(array('id' => 2), array('id' => 1), array('id' => 3)), array('id' => 1) ), array( array(array('id' => 3), array('id' => 2), array('id' => 1)), array('id' => 1) ), ); } public function getDateCollection() { return array( array( array(array('date' => '2014-03-03'), array('date' => '2015-03-02'), array('date' => '2013-03-01')), array('date' => '2013-03-01') ), array( array(array('date' => '2014-02-03'), array('date' => '2013-02-01'), array('date' => '2015-02-02')), array('date' => '2013-02-01') ), ); } /** * @dataProvider getIdCollection */ public function testIdComparator($collection, $expected) { $obj = new ObjectCollection($collection); $obj->setComparator(new IdComparator()); $elements = $obj->sort(); $firstElement = array_shift($elements); $this->assertEquals($expected, $firstElement); } /** * @dataProvider getDateCollection */ public function testDateComparator($collection, $expected) { $obj = new ObjectCollection($collection); $obj->setComparator(new DateComparator()); $elements = $obj->sort(); $firstElement = array_shift($elements); $this->assertEquals($expected, $firstElement); }}
戦略パターンは、主に一連のアルゴリズムを対象とし、各アルゴリズムを共通のインターフェースを持つ独立したクラスにカプセル化して、それらを置き換えることができます。お互い。戦略パターンにより、クライアントに影響を与えることなくアルゴリズムを変更できます。一般に、ストラテジー パターンは、アプリケーションが特定のサービスまたは機能を実装する必要があり、アプリケーションに複数の実装方法がある場合の使用に適しています。