【デザインパターン】Factory Methodパターン・Builderパターン

# はじめに
オブジェクト指向プログラミングのデザインパターンを学習した際の個人的な記事です。
今回は「Factory Method」および「Builderパターン」について学習しました。

## Factory Methodパターン
* 「ペアになるオブジェクトを用意するメソッドを定義する」方法
    * クラスの内部で、別のサブクラスのインスタンスを生成するためのメソッドを定義する
    * サブクラスと別のサブクラスの結合度が高い場合に有用
        * 別のサブクラスを単独でも呼び出す場合、インスタンス化を別クラスで行う理由がわかりにくい
* クラスを継承してサブクラスを作成する場合に用いられる

**コード例**
Macbookの抽象クラスを継承する「MacBook2019」「MacBook2020」は、
それぞれ搭載されるCPUが異なるが、「createCpu」でCPUのオブジェクトを個別に紐付ける。

```php:FactoryMethod.php

<?php
abstract class MacBookFactory{
    abstract protected function createCpu();

    public function getCpu()
    {
        $cpu = $this->createCpu();
        return $cpu->getName();
    }
}

class MacBook2019 extends MacBookFactory
{
    public function createCpu()
    {
        return new IntelCorei7();
    } 
}

class MacBook2020 extends MacBookFactory
{
    public function createCpu()
    {
        return new AppleSilicon();
    }
}

class AppleSilicon
{
    public function getName() { return 'M1' ;}
}

class IntelCorei7
{
    public function getName() { return 'Intel Core i7';}
}

/************* Main *************/
$macBook2019 = new MacBook2019();
$macBook2020 = new MacBook2020();

printf("%s memory is %s\n", get_class($macBook2019), $macBook2019->getCpu());
printf("%s memory is %s\n", get_class($macBook2020), $macBook2020->getCpu());

?>
```

``` command:出力結果
MacBook2019 memory is Intel Core i7
MacBook2020 memory is M1
```
## Builder パターン
* 「正しい生成手順をあらかじめ別の専用クラスにまとめる形で用意しておく」方法
    * 「Builderクラス」と「Directorクラス」から構成される
        * 「Builderクラス」は、コンストラクタを分割したメソッドを持つ
        * 「Directorクラス」は、「Builderクラス」のメソッドを生成手順に従い呼び出す
* コンストラクタのオーバーロードでは対応が複雑な生成ケースに有用

**コード例**
「SmartPhoneInitialBuilder」クラスにコンストラクタの処理を集約し、
「SoftbankSmartPhoneDirector」「SimfreeSmartPhoneDirector」クラスにメソッドの定義する。
 「Directorクラス」でインスタンスを作成し、最終的には共通のSmartPhoneクラスを生成する。

```php:Builder.php
<?php
class SmartPhone{
    private $setup = [];
    public function __construct($setup)
    {
        $this->setup = $setup;
    }
    public function getSetup(){
        return $this->setup;
    }
}

class SoftbankSmartPhoneDirector{
    public function createSmartPhone(SmartPhoneInitialBuilder $builder)
    {
        $setup = [];
        
        $setup[] = $builder->initialize();
        $setup[] = $builder->initializeForSoftbank();
        $setup[] = $builder->finalize();
        $setup[] = $builder->finalizeForSoftbank();

        return new SmartPhone($setup);
    }
}
class SimfreeSmartPhoneDirector{
    public function createSmartPhone(SmartPhoneInitialBuilder $builder)
    {        
        $setup = [];
        
        $setup[] = $builder->initialize();
        $setup[] = $builder->finalize();
        
        return new SmartPhone($setup);
    }
}

class SmartPhoneInitialBuilder {
    public function initializeForSoftbank(){
        return "Softbank用初期化処理";
    }
    public function initialize(){
        return "共通初期化処理";
    }
    public function finalize(){
        return "最終処理";
    }
    public function finalizeForSoftbank(){
        return "Softbank用最終処理";
    }
}

// Main
// Builderクラス
$smartPhoneSimInitialBuilder = new SmartPhoneInitialBuilder();

// Directorクラス
$softbankSmartPhoneDirector  = new SoftbankSmartPhoneDirector();
$simfreeSmartPhoneDirector   = new SimfreeSmartPhoneDirector();

// オブジェクトクラス
$softbankSmartPhone  = $softbankSmartPhoneDirector->createSmartPhone($smartPhoneSimInitialBuilder);
$simfreeSmartPhone   = $simfreeSmartPhoneDirector->createSmartPhone($smartPhoneSimInitialBuilder);

echo "Softbank版". get_class($softbankSmartPhone)."\n";
print_r($softbankSmartPhone->getSetup());

echo "SimFree版". get_class($simfreeSmartPhone)."\n";
print_r($simfreeSmartPhone->getSetup());
?>
```
``` command:出力結果

Softbank版smartPhone
Array
(
    [0] => 共通初期化処理
    [1] => Softbank用初期化処理
    [2] => 最終処理
    [3] => Softbank用最終処理
)
SimFree版smartPhone
Array
(
    [0] => 共通初期化処理
    [1] => 最終処理
)
```

# 参考
1. [Javaデザインパターン徹底攻略(技術評論社)](https://gihyo.jp/book/2002/4-7741-1579-7)
2. [デザインパターン(TECHSCORE)](https://www.techscore.com/tech/DesignPattern/index.html/)