Factoryパターン〜FactoryMethod〜

そこに、Factoryパターン一族

– Simple Factory[正確にはFactoryパターンではない]
– Factory Method
– Abstract Factory
の章があったので、
ぜひアウトプットしたく書きます!

今回はFactory Methodについてです!

Factory Method

オブジェクトを作成をカプセル化し、依存度を下げるために使います。
(Simple Factory、Abstract Factoryと同じ)

オブジェクト作成のためのインターフェースを
抽象クラス(スーパークラス)に定義しますが、
どのクラスをインスタンス化するかについてはサブクラスに決定させます

→抽象クラス(親クラス)は、
サブクラスの作成したオブジェクトを利用するだけで
具体的なオブジェクトが何なのかを知らない。

AbstractFactoryと違う部分
– 継承を使うので、サブクラス(子クラス)が
作成するオブジェクトの具体的な型を実装する。

 

クラス図でみるとこんな感じ

 

factoryMethodはサブクラスに任せるために、
Factoryクラス(スーパークラス)は抽象クラスになる。

クラス図からもわかるように、
Factoryクラス(スーパークラス)は
Prodoctオブジェクトを作成する具体的な方法は全く知りませんが、
factoryMethodを使えばProdoctオブジェクトを作成できることを知っています。
なので、anOperationメソッド内でfactoryMethodを使用することが多いです。

 

 

HeadFirstでは、
地域スタイルでピザの作り方が異なる
フランチャイズでの例がありました。

FactoryMethodのサンプルコード

 

クラス図はこんな感じ。

 

▶︎ PizzaStore(スーパークラス)
Pizzaオブジェクトを作成する具体的な方法は全く知りませんが、
createPizzaメソッドを使えばPizzaオブジェクトを作成できることを知っています。
→orderPizzaメソッド内でcreatePizzaを使用して実装している。

▶︎ NYPizzaStore(PizzaStoreのサブクラス)
具象Pizza(NYスタイル)オブジェクトを作成する

▶︎ChicagoPizzaStore(PizzaStoreのサブクラス)
具象Pizza(Chicagoスタイル)オブジェクトを作成する

▶︎ Pizza
抽象Pizzaクラス。
PizzaStoreのサブクラスにより、具象Pizzaオブジェクトが作成される。

└ NYCheesePizza 具象Pizzaクラス
└ NYClamPizza 具象Pizzaクラス
└ ChicagoCheesePizza 具象Pizzaクラス
└ ChicagoClamPizza 具象Pizzaクラス

 

メリット1:
地域ごとにピザメニューの作り方が異なっても大丈夫

地域ごとの具象PizzaStoreクラス、具象Pizzaクラスがある。
そのため、同じチーズピザでも、
NY店はゴーダチーズ、Chicago店はモッツアレラチーズにしたり
切り方はサブクラスでオーバライドするなど
多種多様に対応することができる。

 

メリット2:
ChicagoにあるけどNY出身者が多い地区のピザ屋にも対応可能

こんなクラスを作ればいい。
– ChicagoPizzaStore_ManyNewYorker.php

class ChicagoPizzaStore_ManyNewYorker extends PizzaStore
{
    public function createPizza(string $type): object
    {
        $pizza = null;
        if ($type == "チーズ(NY風)") {
            $pizza = new NYCheesePizza();
        } else if ($type == "チーズ(Chicago風)") {
            $pizza = new ChicagoCheesePizza();
        } else if ($type == "野菜(NY風)") {
            $pizza = new NYVeggiePizza();
        } else if ($type == "野菜(Chicago風)") {
            $pizza = new ChicagoVeggiePizza();
        }

        return $pizza;
    }
}

 
ピザ食べたくなりました。
やっぱりマルゲリータですよね。

InterfaceとAbstractを使ってみる

「インターフェース」ってよく聞きますが、あんまりわかってないです。
というか全くわかりません、「インターフェース」って言いたいだけです。

PHP conference Kansai2018で
インターフェース再入門」というセッションがあり、
そこから気になりだしたので探ってみます。
会社で、PHP conference Kansai2018共有LTしたので、
もうちょい深いところつつけたらなと思います。

ちなみに過去に私が書いたPHP conference Kansai2018の記事はこちら

PHPカンファレンス関西へ初参戦!

インターフェースとは…

何か目的を果たすための手段となるもの。
中身を知らなくても使う側は使うことができる。

例えば…

ECサイト(「ブーメラン」を売っているお店とする)で考えると

  • 使い手 = 買い手
  • 目的 = 「ブーメラン」をクレジットカードで購入したい
  • 手段 = 決済モジュールのクレジットカード決済

→ この時のインターフェースは「決済モジュール」になります!

例えば…(パート2)

  • 使い手 = わたし
  • 目的 = 青い空の下で音楽を聞きながら、お酒飲みたい!
  • 手段 = フェスに行く

→ この時のインターフェースは「フェス」になります!

↑をPHPで書いてみます!
〜InterfaceとAbstract使って〜

実際に書いてたらabstractとの違いがわかんなくなってきたので、両方使ってみます。

参考:
https://havelog.ayumusato.com/develop/php/e166-php-interface-abstract.html

\  Github – kin29/fes  /

  • GoodFesInterface.php             ←Interface。
  • AbstractFes.php                        ←Abstract。(WildBunchFesの継承クラス)
  • WildBunchFes.php                  ← AbstractFesを継承し、GoodFesInterfaceを使用
  • Watashi.php                              ←わたし(使い手)

◎ 前提

「青い空の下で音楽を聞きながら、お酒飲みたい!」という、
わたしの願いを叶えるための良いフェスの必須条件を
GoodFesInterface.php」  にこめています。

さらに、わたしが今年の夏に楽しんだフェス
「WildBunchFes(通称WBF)」 「CircleFukuoka」 「まつり宮崎」 「AoshimaBeachParkFes」。
これら4つに共通するもの、
「音楽」 「酒」 「晴れ」 「野外」 「フェスの名前」 「思い出」を
AbstractFesクラス」 に詰め込んで各Fesで継承しています。

 

GoodFesInterface.php [Interface]

<?php

namespace Fes;

interface GoodFesInterface
{
    public function isMusic();

    public function isDrink();

    public function isSunny();

    public function isOutdoor();
}

 

AbstractFes.php [Abstract class]

<?php

namespace Fes;

abstract class AbstractFes
{
    public $fes_name;
    public $music;
    public $drink;
    public $place;
    public $weather;
    public $memory;

    public function __construct()
    {
        $this->place = '野外';
        $this->weather = '快晴';
        $this->memory = 'フェス最高 ^ω^';
    }

    /**
     * @return string
     */
    public function getFesName()
    {
        return $this->fes_name;
    }

    /**
     * @return bool
     */
    public function isMusic()
    {
        return isset($this->music);
    }

    /**
     * @return bool
     */
    public function isDrink()
    {
        return isset($this->drink);
    }

    /**
     * @return bool
     */
    public function isOutdoor()
    {
        return ($this->place === '野外');
    }

    /**
     * @return bool
     */
    public function isSunny()
    {
        return ($this->weather === '快晴');
    }

    /**
     * @return string
     */
    public function getMemory()
    {
        return $this->memory;
    }
}

 

WildBunchFes.php

<?php

namespace Fes;

class WildBunchFes extends AbstractFes implements GoodFesInterface
{
    public $fes_name;
    public $music;
    public $drink;
    public $memory;

    public function __construct()
    {
        parent::__construct();
        $this->fes_name = '「ワイルドバンチ」';
        $this->music = 'ヤバT/サカナクション/スカパラ/10-FEET/フォーリミ/teto/ハルカミライ...etc';
        $this->drink = 'ビール、ビール';
        $this->memory = 'しかし、2日目は台風直撃で中止になりました。';
    }
}

 

Watashi.php

<?php

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

use Fes\WildBunchFes;
...


class Wahatashi
{
    public $wbf;
    ...

    public function __construct()
    {
        $this->wbf = new WildBunchFes();
        ...
    }

    public function done()
    {
        $arrRet = array();
        $arrRet[get_class($this->wbf)] = $this->doneList($this->wbf);
        ...

        var_dump($arrRet);
    }

    public function doneList($class)
    {
        $arrRet = array();
        foreach ($this->arrDoList as $item){
            $arrRet[$item] = $class->{$item}();
        }
        return $arrRet;
    }
}

$i_am = new Wahatashi();
$i_am->done();

Watashi.phpは、
WildBunchFesクラスを通して、GoodFesInterfaceを使って(手段)として、
目的を果たしています。ですよね?w

 

まだまだ私の理解が乏しく、間違っている部分もあるかと思います。
そして、「こんなソースいつ使うんだ?」って感じですが、
自分の好きなものでソースを書くってなかなか面白かったです。

みなさんもぜひしてみてください! \(^^)/