【PHPデザインパターン】09_Builder～生成の手順と手段を分離する

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

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

> [Do You PHP はてな〜[doyouphp][phpdp]PHPによるデザインパターン入門 - Builder～生成の手順と手段を分離する](http://d.hatena.ne.jp/shimooka/20141216/1418706609)

# 概要
- 「手順」と「材料」を分けておき、同じ手順で異なるオブジェクトを生成させる。
- オブジェクトを「何を生成するか」と「どのように生成するか」に分離する。

## 構成要素
### Builderクラス
オブジェクトの「生成手段」を提供するクラス群で最上位に位置するクラス。

### ConcreteBuilderクラス
- Builderクラスで提供されるAPIを実装するサブクラス。
- 生成したオブジェクトを取得するためのメソッドを提供する。

### Directorクラス
- Builderクラスで定義されたAPIを使ってオブジェクトを生成するクラス。

### Productクラス
- 最終的に生成されるオブジェクトのクラス。

# 実演
## 処理の流れ
- 配列型の商品データを受け取り、Itemオブジェクトを生成する。
- Itemオブジェクトからメッセージを生成する。
- Productクラスに相当するクラスはない？（生成されるのはItemオブジェクトの配列）

## ファイル構造
```sh
MyBuilder
  ├── ArrayItemBuilder.php
  ├── Item.php
  ├── ItemBuilder.php
  ├── ItemDirector.php
  └── my_client.php
```

## ソースコード
### Builderクラス
#### ItemBuilder.php
```ItemBuilder.php
<?php
namespace DoYouPhp\PhpDesignPattern\Builder\MyBuilder;

// Builderクラスに相当する
// インターフェイスのため、メソッドの実装はサブクラスで行う
interface ItemBuilder
{
    public function parse($data);
}
```

### ConcreteBuilderクラス
#### ArrayItemBuilder.php
```ArrayItemBuilder.php
<?php
namespace DoYouPhp\PhpDesignPattern\Builder\MyBuilder;

use DoYouPhp\PhpDesignPattern\Builder\MyBuilder\ItemBuilder;
use DoYouPhp\PhpDesignPattern\Builder\MyBuilder\Item;

// ConcreteBuilderクラスに相当する
// インターフェイスで定義されたメソッドを実装する
// オブジェクトの具体的な生成手段を提供し、生成されたオブジェクトを取得する
// 生成手段を変更したい場合は、このクラスを別のConcreteBuilderクラスへ切り替えれば良い
class ArrayItemBuilder implements ItemBuilder
{
    // 受け取った配列データをItemオブジェクトの配列として生成する
    public function parse($data)
    {
        foreach ($data as $value) {
            $list[] = new Item($value['id'], $value['name'], $value['price']);
        }

        return $list;
    }
}
```

### Directorクラス
#### ItemDirector.php
```ItemDirector.php
<?php
namespace DoYouPhp\PhpDesignPattern\Builder\MyBuilder;

use DoYouPhp\PhpDesignPattern\Builder\MyBuilder\ItemBuilder;

// Directorクラスに相当する
// オブジェクトの生成手順を提供する
class ItemDirector
{
    private $builder;
    private $data;

    // 第1引数はItemBuilderオブジェクト
    // 第2引数はテストデータ
    // それぞれをプロパティとしてセットする
    public function __construct(ItemBuilder $builder, $data)
    {
        $this->builder = $builder;
        $this->data = $data;
    }

    // ArrayItemBuilderで実装されているメソッドを使用したメソッド
    // Itemオブジェクトの配列を返す
    public function getItem()
    {
        $item_list = $this->builder->parse($this->data);

        return $item_list;
    }
}
```

### Modelクラス
#### Item.php
```Item.php
<?php
namespace DoYouPhp\PhpDesignPattern\Builder\MyBuilder;

// 1つのItemを表すクラス
class Item
{
    private $id;
    private $name;
    private $price;

    // コンストラクタ
    // 各プロパティをセットする
    public function __construct($id, $name, $price)
    {
        $this->id    = $id;
        $this->name  = $name;
        $this->price = $price;
    }

    // 各プロパティの値を呼び出すメソッド
    public function getId()
    {
        return $this->id;
    }

    public function getName()
    {
        return $this->name;
    }

    public function getPrice()
    {
        return $this->price;
    }
}
```

### Clientクラス
#### my_client.php
```my_client.php
<?php
namespace DoYouPhp\PhpDesignPattern\Builder\MyBuilder;

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

use DoYouPhp\PhpDesignPattern\Builder\MyBuilder\ArrayItemBuilder;
use DoYouPhp\PhpDesignPattern\Builder\MyBuilder\ItemDirector;

// ItemBuilderインスタンスを生成する
// 配列形式のテストデータを作成する
$builder = new ArrayItemBuilder();
$data_array = array(
    0 => array(
        'id'    => 1, 
        'name'  => 'apple', 
        'price' => 100,
    ),
    1 => array(
        'id'    => 2, 
        'name'  => 'orange', 
        'price' => 80,
    ),
);

// 第1引数はItemBuilderインスタンス
// 第2引数はテストデータ
$director = new ItemDirector($builder, $data_array);
foreach ($director->getItem() as $item) {
    printf('ID:%d, 商品名:%s, 価格:%d%s', $item->getId(), $item->getName(), $item->getPrice(),'<br>'."\n");
}
```