首頁 >後端開發 >php教程 >一文讀懂簡單工廠、工廠方法、抽象工廠

一文讀懂簡單工廠、工廠方法、抽象工廠

齐天大圣
齐天大圣原創
2020-07-31 08:39:221939瀏覽

簡單工廠模式

#基本上每個人手機裡都有一款音樂播放器,目前流行的播放器有:QQ音樂、酷狗音樂、搜狗音樂、網易雲音樂、天天動聽等。以下是一段關於播放音樂的程式碼:

if ($type == 'QQ') {
    $player = new QQPlayer();
} else if ($type == 'Wy') {
    $player = new WyPlayer();
} else if ($type == 'KG') {
    $player = new KGPlayer();
} else {
    $palyer = null;
}
 
$player->on();  // 打开播放器
$player->choiceMusic('我不配');  // 选择歌曲
$player->play();  // 开始播放

為了時程式碼的邏輯更加清晰、可讀性更好,我們要善於把功能獨立的程式碼區塊封裝成函數。依照這個設計思路,​​我們可以將其中的條件分支抽離出來,並單獨放在一個類別中的方法中。這個類,我們就可以叫做簡單工廠模式。

簡單工廠模式的定義:一個類別可以根據不同的參數來取得不同的實例,一般這些被建立的實例都有相同的父類別。

靜態工廠模式:一般的,我們將簡單工廠模式中的用於建立不同實例的方法設定為靜態方法,避免建立多個相同實例。

下面我們用簡單工廠模式改寫上面的程式碼

class MusicPlayerFactory
{
    public static function create ($type)
    {
        if ($type == 'QQ') {
            $player = new QQPlayer();
        } else if ($type == 'Wy') {
            $player = new WyPlayer();
        } else if ($type == 'KG') {
            $player = new KGPlayer();
        } else {
            $player = null;
        }
        return $player;
    }
}

// 业务代码修改如下
$player = MusicPlayerFactory:create('QQ');
$player->on();  // 打开播放器
$player->choiceMusic('我不配');  // 选择歌曲
$player->play();  // 开始播放

對於上面的簡單工廠模式,如果我們需要新增新的音樂播放器,就一定會修改MusicPlayerFactory的create方法,有點不符合「開閉原則」。對於這種條件分支不是很多,另外類別的創建也非常的簡單,使用簡單工廠模式是完全可以的。如果非要將if分支邏輯去掉,使他符合“開閉原則”,那麼就可以使用工廠方法來實現。對於工廠方法,也不是一定比簡單工廠模式好,雖然它的擴展性比較好,但是犧牲了可讀性。

工廠方法模式

定義:在工廠方法模式中,工廠父類負責定義建立產品物件的公共接口,而工廠子類別則負責產生具體的產品對象,這樣做的目的是將產品類別的實例化操作延遲到工廠子類別中完成,即透過工廠子類別來確定究竟應該實例化哪一個具體產品類別。

現在我們用「多型」來消除上面簡單工廠模式的if分支結構。實現的程式碼如下所示:

interface IMusicPlayerFactory
{
    static function create ();
}

class QQPlayerFactory implements IMusicPlayerFactory
{
    public static function create ()
    {
        return new QQPlayer();
    }
}

class WyPlayerFactory implements IMusicPlayerFactory
{
    public static function create ()
    {
        return new WyPlayer();
    }
}

class KGPlayerFactory implements IMusicPlayerFactory
{
    public static function create ()
    {
        return new KGPlayer();
    }
}

// 业务代码修改如下
if ($type == 'QQ') {
    $player = QQPlayerFactory::create();
} else if ($type == 'Wy') {
    $player = WyPlayerFactory::create();
} else if ($type == 'KG') {
    $player = KGPlayerFactory::create();
} else {
    throw new \Exception('...');
}
$player->on();  // 打开播放器
$player->choiceMusic('我不配');  // 选择歌曲
$player->play();  // 开始播放

可以看到,問題又回到了原點,業務程式碼裡又出現了if條件分支結構。那怎麼去解決該問題呢?

我們可以為工廠類別再建立一個簡單工廠,用來建立工廠類別物件。新的簡單工廠程式碼如下:

class MusicPlayerFactoryMap
{
    const Players = [
        'QQ' => 'QQPlayerFactory',
        'Wy' => 'WyPlayerFactory',
        'KG' => 'KGPlayerFactory'
    ];
    public static function getPlayerFactory (string $type)
    {
        if (empty($type)) {
            return null;
        }
        return (self::Players[$type])::create();
    }
}

// 业务代码修改如下
$palyer = MusicPlayerFactoryMap::getPlayerFactory('QQ')
$player->on();  // 打开播放器
$player->choiceMusic('我不配');  // 选择歌曲
$player->play();  // 开始播放

可以看到,使用了工廠模式,結構變的比之前複雜的多。如果來的創建實例過程複製,我們才會建議使用工廠方法模式。

抽象工廠模式

抽象工廠模式使用場景比較特殊,用的比較少。在工廠方法模式中,具體工廠負責生產特定的產品,每一個工廠對應一個特定產品。但有時候,我們需要一個工廠可以創造多個產品對象,而不是單一的產品。

我們用一個例子來看:物件電腦廠是負責生產電腦來出售的。我們知道,電腦是由主機、鍵盤、顯示器以及滑鼠組成的,目前物件電腦城只生產3種電腦,低配、中配和高配的,不同配置的電腦使用的主機品牌、顯示器品牌等都是不同的。

主機目前有:麒麟主機、雷霆主機、冬日主機

鍵盤目前有:雷柏、羅技、雷蛇

顯示器目前有:aoc、hkc、BenQ

滑鼠目前有:羅技、靈蛇、方正

頂配版電腦由麒麟主機、雷柏鍵盤、aoc顯示器、羅技滑鼠組成,中配由…。

關於主機的程式碼如下:

interface Host
{
    static function createHost ();
}
class DrHost implements Host
{
    public static function createHost()
    {
        echo '创建冬日主机' . PHP_EOL;
    }
}
class QlHost implements Host
{
    public static function createHost()
    {
        echo '创建麒麟主机' . PHP_EOL;
    }
}
class LtHost implements Host
{
    public static function createHost()
    {
        echo '创建雷霆主机' . PHP_EOL;
    }
}

類似的,去建立鍵盤、顯示器、滑鼠,程式碼這裡就不貼了。

現在,我們定義一個建立電腦的介面。

interface ComputerFactory
{
    static function createHost ();
    static function createKeyboard ();
    static function createMonitor ();
    static function createMouse ();
}

然後完成三個特定工廠用於創建低配、中配以及高配版電腦。

class GreatComputerFactory implements ComputerFactory
{
    public static function createHost()
    {
        QlHost::createHost();
    }
    public static function createKeyboard()
    {
        LbKeyboard::createKeyboard();
    }
    public static function createMonitor()
    {
        AocMonitor::createMonitor();
    }
    public static function createMouse()
    {
        LjMouse::createMouse();
    }
}
class GoodComputerFactory implements ComputerFactory
{
    public static function createHost()
    {
        LtHost::createHost();
    }
    public static function createKeyboard()
    {
        LjKeyboard::createKeyboard();
    }
    public static function createMonitor()
    {
        HkcMonitor::createMonitor();
    }
    public static function createMouse()
    {
        LsMouse::createMouse();
    }
}
class NormalComputerFactory implements ComputerFactory
{
    public static function createHost()
    {
        DrHost::createHost();
    }
    public static function createKeyboard()
    {
        LsKeyboard::createKeyboard();
    }
    public static function createMonitor()
    {
        BenqMonitor::createMonitor();
    }
    public static function createMouse()
    {
        FzMouse::createMouse();
    }
}

現在可以來建立特定的電腦了

class GreatComputer
{
    public function __construct()
    {
        echo '高配电脑' . PHP_EOL;
        GreatComputerFactory::createHost();
        GreatComputerFactory::createKeyboard();
        GreatComputerFactory::createMonitor();
        GreatComputerFactory::createMouse();
    }
}
class GoodComputer
{
    public function __construct()
    {
        echo '中配电脑' . PHP_EOL;
        GoodComputerFactory::createHost();
        GoodComputerFactory::createKeyboard();
        GoodComputerFactory::createMonitor();
        GoodComputerFactory::createMouse();
    }
}
class NormalComputer
{
    public function __construct()
    {
        echo '低配电脑' . PHP_EOL;
        NormalComputerFactory::createHost();
        NormalComputerFactory::createKeyboard();
        NormalComputerFactory::createMonitor();
        NormalComputerFactory::createMouse();
    }
}

以上是一文讀懂簡單工廠、工廠方法、抽象工廠的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn