【PHPデザインパターン】22_Strategy～戦略を切り替える

# 引用記事
この記事を書くきっかけになったブログです。

記事内の解説やソースコードは、こちらのブログと著者の公開リポジトリを参考にしています。

> [Do You PHP はてな〜[doyouphp][phpdp]PHPによるデザインパターン入門 - Strategy～戦略を切り替える](http://d.hatena.ne.jp/shimooka/20141219/1418965548)

# 概要
- 「strategy」は「戦略」「方針」という意味。
- アルゴリズムをクラスとして定義し、切り替えられるようにする。
- それぞれの処理がクラスにまとめられて実装されるので、コードは処理内容に専念することができる。

## 構成要素
### Strategyクラス
- それぞれの処理に共通のAPIを定義するクラス。

### ConcreteStrategyクラス
- Strategyクラスのサブクラス。

### Contextクラス
- Strategy型のオブジェクトを内部に保持し、具体的な処理をそのオブジェクトに委譲するクラス。

# 実演
## 処理の流れ
- データを読み込み、``ItemDataContext型オブジェクト``を生成する。
- 読み込みむためのアルゴリズムをデータ形式で分ける。
- ``ReadArrayStrategyクラス``は配列データを読み込む。
- ``ReadStringStrategyクラス``は文字列データを読み込む。

## ファイル構造
```sh
MyStrategy
  ├── ItemDataContext.php
  ├── ReadArrayStrategy.php
  ├── ReadItemDataStrategy.php
  ├── ReadStringStrategy.php
  └── my_client.php
```

## ソースコード
### Strategyクラス
#### ReadItemDataStrategy.php
```ReadItemDataStrategy.php
<?php
namespace DoYouPhp\PhpDesignPattern\Strategy\MyStrategy;

/**
 * Strategyに相当する
 */
abstract class ReadItemDataStrategy
{
    private $item_data;

    // コンストラクタ
    public function __construct($item_data)
    {
        $this->itemData = $item_data;
    }

    // データを読み込み、stdClass型オブジェクトを要素とする配列を返す
    public function getData()
    {
        return $this->readData($this->getitemData());
    }

    // 元データを返す
    public function getitemData()
    {
        return $this->itemData;
    }

    // ConcreteStrategyに実装させるメソッド
    abstract protected function readData($item_data);
}
```

### ConcreteStrategyクラス
#### ReadArrayStrategy.php
```ReadArrayStrategy.php
<?php
namespace DoYouPhp\PhpDesignPattern\Strategy\MyStrategy;

use DoYouPhp\PhpDesignPattern\Strategy\MyStrategy\ReadItemDataStrategy;

/**
 * ConcreteStrategyに相当する
 * 配列形式のデータを読み込む
 */
class ReadArrayStrategy extends ReadItemDataStrategy
{
    // データを読み込み、stdClass型オブジェクトを要素とする配列を返す
    protected function readData($item_data)
    {
        foreach($item_data as $item_name) {
          $obj = new \stdClass();
          $obj->item_name = $item_name;

          $return_value[] = $obj;
        }

        return $return_value;
    }
}
```

#### ReadStringStrategy.php
```ReadStringStrategy.php
<?php
namespace DoYouPhp\PhpDesignPattern\Strategy\MyStrategy;

use DoYouPhp\PhpDesignPattern\Strategy\MyStrategy\ReadItemDataStrategy;

/**
 * ConcreteStrategyに相当する
 * 文字列形式のデータを読み込む
 */
class ReadStringStrategy extends ReadItemDataStrategy
{
    // データを読み込み、stdClass型オブジェクトを要素とする配列を返す
    protected function readData($item_data)
    {
        $item_array = explode(",", $item_data);

        foreach($item_array as $item_name) {
          $obj = new \stdClass();
          $obj->item_name = $item_name;

          $return_value[] = $obj;
        }
        
        return $return_value;
    }
}
```

### Contextクラス
#### ItemDataContext.php
```ItemDataContext.php
<?php
namespace DoYouPhp\PhpDesignPattern\Strategy\MyStrategy;

use DoYouPhp\PhpDesignPattern\Strategy\MyStrategy\ReadItemDataStrategy;

/**
 * Contextに相当する
 * Strategy型オブジェクトを保持する
 */
class ItemDataContext
{
    private $strategy;

    // コンストラクタ
    public function __construct(ReadItemDataStrategy $strategy)
    {
        $this->strategy = $strategy;
    }

    // 各ConcreteStrategyで生成されたデータを返す
    public function getItemData()
    {
        return $this->strategy->getData();
    }
}
```

### Client
#### my_client.php
```my_client.php
<?php
namespace DoYouPhp\PhpDesignPattern\Strategy\MyStrategy;

require dirname(dirname(__DIR__)).'/vendor/autoload.php';

use DoYouPhp\PhpDesignPattern\Strategy\MyStrategy\ItemDataContext;
use DoYouPhp\PhpDesignPattern\Strategy\MyStrategy\ReadArrayStrategy;
use DoYouPhp\PhpDesignPattern\Strategy\MyStrategy\ReadStringStrategy;

// データ出力用メソッド
function dumpData($data)
{
    foreach ($data as $object) {
        echo $object->item_name.'<br>'."\n";
    }
}

// テスト用データ
$item_array  = array('apple', 'orange', 'peach');
$item_string = 'apple,orange,peach';

// 配列からオブジェクトを生成する
echo '--- 配列から生成したデータ ---'.'<br>'."\n";
$strategy = new ReadArrayStrategy($item_array);
$context = new ItemDataContext($strategy);
dumpData($context->getItemData());

// 文字列からオブジェクトを生成する
echo '--- 文字列から生成したデータ ---'.'<br>'."\n";
$strategy = new ReadStringStrategy($item_string);
$context = new ItemDataContext($strategy);
dumpData($context->getItemData());
```