簡單工廠模式
#基本上每個人手機裡都有一款音樂播放器,目前流行的播放器有: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中文網其他相關文章!