一文读懂简单工厂、工厂方法、抽象工厂
簡單工廠模式
基本上每個人手機里都有一款音樂播放器,目前流行的播放器有: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();
}
}
總結
以上是生活随笔為你收集整理的一文读懂简单工厂、工厂方法、抽象工厂的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: iPhone手机型号,藏着的秘密,你知道
- 下一篇: 遇险时我们该如何用苹果iPhone求救?