1. 程式人生 > >PHP設計模式(二)——工廠模式(Factor Pattern)

PHP設計模式(二)——工廠模式(Factor Pattern)

@[TOC](PHP設計模式(二)——工廠模式(Factor Pattern))

工廠模式(Factor Pattern),就是負責生成其他物件的類或方法

(一)為什麼需要工廠模式

  1. 工廠模式可以將物件的生產從直接new 一個物件,改成通過呼叫一個工廠方法生產。這樣的封裝,程式碼若需修改new的物件時,不需修改多處new語句,只需更改生產物件方法。
  2. 若所需例項化的物件可選擇來自不同的類,可省略if-else多層判斷,給工廠方法傳入對應的引數,利用多型性,例項化對應的類。

(二)簡單實現程式碼

// 工廠類
class Factor
{
    static function createDb()
    {
        echo '我生產了一個例項——';
        return new DB();
    }
}

// 資料庫類
class DB
{
    public function __construct()
    {
        echo __CLASS__.PHP_EOL;
    }
}

$db = Factor::createDb();

(三)實現一個運算器

// 抽象運算類
abstract class Operation
{
    abstract public function getVal($i, $j);
}

// 繼承抽象類的 加法類
class OperationAdd extends Operation
{
    public function getVal($i, $j)
    {
        return $i + $j;
    }
}

// 繼承抽象類的 減法類
class OperationSub extends Operation
{
    public function getVal($i, $j)
    {
        return $i - $j;
    }
}

// 計算器工廠
class CounterFactor
{
    private static $operation;

    // 工廠生產特定類物件方法
    static function createOperation(string $operation)
    {
        switch ($operation) {
            case '+' :
                self::$operation = new OperationAdd();
                break;
            case '-' :
                self::$operation = new OperationSub();
                break;
        }
        return self::$operation;
    }
}

$counter = CounterFactor::createOperation('-');
echo $counter->getVal(1, 2);

缺點:若是再增加一個乘法運算,除了增加一個乘法運算類之外,還得去工廠生產方法裡面新增對應的case程式碼,違反了開放-封閉原則。

解決方法(1):通過傳入指定類名

abstract class Operation
{
    abstract public function getVal($i, $j);
}

// 繼承抽象類的 加法類
class OperationAdd extends Operation
{
    public function getVal($i, $j)
    {
        return $i + $j;
    }
}

// 繼承抽象類的 減法類
class OperationSub extends Operation
{
    public function getVal($i, $j)
    {
        return $i - $j;
    }
}

// 繼承抽象類的 乘法類
class OperationMul extends Operation
{
    public function getVal($i, $j)
    {
        return $i * $j;
    }
}

// 計算器工廠
class CounterFactor
{
    // 工廠生產特定類物件方法
    static function createOperation(string $operation)
    {
        return new $operation;
    }
}

$counter = CounterFactor::createOperation('OperationMul');
echo $counter->getVal(1, 2);

解決方法(2):通過抽象工廠模式

抽象高於實現

其實我們完全可以抽象出一個抽象工廠,然後將對應的物件生產交給子工廠實現。程式碼如下

<?php

abstract class Operation
{
    abstract public function getVal($i, $j);
}

// 繼承抽象類的 加法類
class OperationAdd extends Operation
{
    public function getVal($i, $j)
    {
        return $i + $j;
    }
}

// 繼承抽象類的 減法類
class OperationSub extends Operation
{
    public function getVal($i, $j)
    {
        return $i - $j;
    }
}

// 繼承抽象類的 乘法類
class OperationMul extends Operation
{
    public function getVal($i, $j)
    {
        return $i * $j;
    }
}

// 繼承抽象類的 除法類
class OperationDiv extends Operation
{
    public function getVal($i, $j)
    {
        return $i / $j;
    }
}

// 抽象工廠類
abstract class Factor
{
    abstract static function getInstance();
}

// 加法子工廠
class AddFactor extends Factor
{
    // 工廠生產特定類物件方法
    static function getInstance()
    {
        return new OperationAdd();
    }
}

// 減法子工廠
class SubFactor extends Factor
{
    // 工廠生產特定類物件方法
    static function getInstance()
    {
        return new OperationSub();
    }
}

// 乘法子工廠
class MulFactor extends Factor
{
    // 工廠生產特定類物件方法
    static function getInstance()
    {
        return new OperationMul();
    }
}

// 除法子工廠
class DivFactor extends Factor
{
    // 工廠生產特定類物件方法
    static function getInstance()
    {
        return new OperationDiv();
    }
}

echo AddFactor::getInstance()->getVal(1, 2).PHP_EOL;
echo SubFactor::getInstance()->getVal(1, 2).PHP_EOL;
echo MulFactor::getInstance()->getVal(1, 2).PHP_EOL;
echo DivFactor::getInstance()->getVal(1, 2).PHP_EOL;