コラム

Factory Method ファクトリーメソッドパターンでインスタンスの生成も任せてしまう

※この記事の注意事項
・できるだけ初心者の方が理解しやすいように、細かい説明は省略しております。
・最後まで読み進められるように、多少ユーモアを交えて表現していることがあります。

========================================

Factory Method ファクトリーメソッドパターンは、テンプレートメソッドパターンに似ているのですが、ファクトリー=クラスを作る工場を意味しています。

処理を利用するユーザー側で、どのクラスからインスタンスをつくるのか考えなくても利用できるようにしたものです。

例えば決済処理などで、クレジット会社からカード番号を基に残高照会を行い、残高から購入金額を引き、決済後の残高を返すといったようなプログラムがあるとします。

この場合、カード会社が変わっても、残高照会購入金額の決済決済後の残高表示という処理は変わりません。

カード会社ごとにAPI通信の方法や、返ってくる値の形式は違う可能性があります。

ですので、インターフェイスだけを定めて、どのカード会社の処理を行うかはサブクラスを作成してそこで判定させるようにします。

コードは以下のようになります。
・インターフェイスを定める interface payInterface 
・カード会社判定クラス class payFactory
・VISAカードのクラス class payVisa implements payInterface
・MASTERカードのクラス class payMaster implements payInterface

interface payInterface
{
    //決済計算をする
    public function payCalculation($price);
    
    //決済結果を表示する
    public function payView();
}

//カード番号から判定を行い、適切なインスタンスを作成する
class payFactory
{
    public function create($number)
    {
        return $this->createPay($number);
    }

    //カード番号で判定を行う
    private function createPay($number)
    {
        if (substr($number, 0, 1) == 4) {
            return new payVisa($number);
        } elseif (substr($number, 0, 1) == 5) {
            return new payMaster($number);
        } else {
            die('このカードは有効なカードではありません');
        }
    }
}

//VISAカード用のAPI処理クラス
class payVisa implements payInterface
{
    //カード番号
    private $number;

    //現在の残高
    private $zandaka;

    public function __constract($number)
    {
        if (empty($number)) {
            throw new Exception('不正なカード番号です');
        }

        $this->number = $number;
    }

    public function payCalculation($price = 0)
    {
        //API通信し、残高を取得する
        //テスト用に残高を 10000円とする
        $this->zandaka = 10000;

        if ($this->zandaka < $price) { die('残高が不足しています'); } $this->zandaka -= $price;

        return $this->zandaka;
    }
    
    public function payView()
    {
        echo 'VISA 残高 '.$this->zandaka;
    }
}

//MASTERカード用のAPI処理クラス
class payMaster implements payInterface
{
    //カード番号
    private $number;

    //現在の残高
    private $zandaka;

    public function __constract($number)
    {
        if (empty($number)) {
            throw new Exception('不正なカード番号です');
        }

        $this->number = $number;
    }

    public function payCalculation($price = 0)
    {
        //API通信し、残高を取得する
        //テスト用に残高を 2000円とする
        $this->zandaka = 2000;

        if ($this->zandaka < $price) { die('残高が不足しています'); } $this->zandaka -= $price;

        return $this->zandaka;
    }
    
    public function payView()
    {
        echo 'MASTERカード 残高は '.$this->zandaka.'円です。';
    }
}

呼び出し側は以下のようになります。

カード番号を4から始まる番号にした場合

//カード番号から判定を行い、カード会社のインスタンスを返す
$instance = new payFactory();
$pay = $instance->create('4567890123');

//カード会社のインスタンスで計算と表示を行う
$pay->payCalculation('1080');
$pay->payView(); //VISA 残高 8920

カード番号を5から始まる番号にした場合

//カード番号から判定を行い、カード会社のインスタンスを返す
$instance = new payFactory();
$pay = $instance->create('5567890123');

//カード会社のインスタンスで計算と表示を行う
$pay->payCalculation('1080');
$pay->payView(); //MASTERカード 残高は 920円です。

カード会社判定用のpayFactoryインスタンスを作成して処理を行っています。カード会社のインスタンスは直接作成していません。payFactoryインスタンスに任せてしまっています。

これにより、決済の使用側からは、カード会社ごとのインスタンスの作成や処理を意識することなく利用することができます。

また、結果の表示フォーマットも、カード会社ごとに変えることができます。

注目すべきは、カード会社ごとにクラスが分かれているので、他のカード会社に影響を与えないように変更を加えたり修正することができる点です。
これはメンテナンス性に優れているパターンと言えます。

========================================

▼PHPのオブジェクト指向とデザインパターン記事一覧

関連記事

コメント

  • トラックバックは利用できません。

  • コメント (0)

  1. この記事へのコメントはありません。