工廠方法模式依賴於繼承,因為物件建立 委託給 實現工廠方法建立物件 的子類
在上面的URL類圖中,Creator
需要 Product
物件的 Product1
類不直接例項化類。相反,它 Creator
指的是單獨 factoryMethod()
建立一個產品物件,這使得Creator
獨立於哪個具體類被例項化。Creator
可以重新定義要例項化的類的子類。在這個例子中,Creator1
子類factoryMethod()
通過例項化類來實現抽象Product1
。
上面簡述一個工廠工作的流程,重點請看下面
1. 簡單工廠模式
- 模式定義: 簡單工廠模式(Simple Factory Pattern):又稱為靜態工廠方法(Static Factory Method)模式,之所以可以這麼說,是因為簡單工廠模式是通過一個靜態方法來建立物件的。它屬於類建立型模式。在簡單工廠模式中,可以根據引數的不同返回返回不同類的例項。簡單工廠模式專門定義一個類來負責建立其他類的例項,被建立的例項通常都具有共同的父類。
- 模式結構
- Factory:工廠角色
工廠角色負責實現建立所有例項的內部邏輯
- Product:抽象產品角色
抽象產品角色是所建立的所有物件的父類,負責描述所有例項所共有的公共介面
- ConcreteProduct:具體產品角色
具體產品角色是建立目標,所有建立的物件都充當這個角色的某個具體類的例項。
舉個栗子
我們想建立一個工廠,這個工廠呢可以生產貓和狗!通常情況下我們會怎麼做呢
interface animals // 抽象產品角色
{
public function animal();
}
class Cat implements animals // 具體產品角色
{
public function animal()
{
return "貓貓";
}
}
class Dog implements animals // 具體產品角色
{
public function animal()
{
return "狗狗";
}
}
class Factory // 工廠角色
{
public static function createAnimal($param)
{
$result = null;
switch($param)
{
case 'cat':
$result = new Cat();
break;
case 'dog':
$result = new Dog();
break;
}
return $result;
}
}
echo Factory::createAnimal("cat")->animal(); // 貓貓
echo Factory::createAnimal("dog")->animal(); // 狗狗
複製程式碼
上面的例子中所講到的就是 簡單工廠(靜態工廠) <還請大佬批評>
簡單工廠適用環境
- 工廠類負責建立的物件比較少:由於建立的物件較少,不會造成工廠方法中的業務邏輯太過複雜。
- 客戶端只知道傳入工廠類的引數,對於如何建立物件不關心:客戶端既不需要關心建立細節,甚至連類名都不需要記住,只需要知道型別所對應的引數。
2. 工廠方法模式
工廠方法模式(Factory Method Pattern)又稱為工廠模式,也叫虛擬構造器(Virtual Constructor)模式或者多型工廠(Polymorphic Factory)模式,它屬於類建立型模式。在工廠方法模式中,工廠父類負責定義建立產品物件的公共介面,而工廠子類則負責生成具體的產品物件,這樣做的目的是將產品類的例項化操作延遲到工廠子類中完成,即通過工廠子類來確定究竟應該例項化哪一個具體產品類。
舉個栗子:
abstract class animals // 抽象產品類
{
abstract public function animal();
}
class Cat extends animals // 具體產品類
{
public function animal()
{
return "貓貓";
}
}
class Dog extends animals // 具體產品類
{
public function animal()
{
return "狗狗";
}
}
interface Factory // 抽象工廠類, 將物件的建立抽象成一個介面
{
public function create();
}
class CatFactory implements Factory // 繼承工廠類, 用於例項化產品
{
public function create()
{
return new Cat();
}
}
class DogFactory implements Factory // 繼承工廠類, 用於例項化產品
{
public function create()
{
return new Dog();
}
}
class Client // 具體操作類
{
public function test()
{
$catResult = new CatFactory();
echo $catResult->create()->animal();
$DogResult = new DogFactory();
echo $DogResult->create()->animal();
}
}
$lala = new Client();
$lala->test(); // 貓貓狗狗
複製程式碼
定義一個用於建立物件的介面,讓子類決定哪個類例項化。 他可以解決簡單工廠模式中的封閉開放原則問題。
【工廠方法模式與簡單工廠模式】
- 工廠方法模式與簡單工廠模式再結構上的不同不是很明顯。工廠方法類的核心是一個抽象工廠類,而簡單工廠模式把核心放在一個具體類上。
- 工廠方法模式之所以有一個別名叫多型性工廠模式是因為具體工廠類都有共同的介面,或者有共同的抽象父類。
- 當系統擴充套件需要新增新的產品物件時,僅僅需要新增一個具體物件以及一個具體工廠物件,原有工廠物件不需要進行任何修改,也不需要修改客戶端,很好的符合了”開放-封閉”原則。而簡單工廠模式在新增新產品物件後不得不修改工廠方法,擴充套件性不好。
- 工廠方法模式退化後可以演變成簡單工廠模式。
3. 抽象工廠模式
抽象工廠模式(Abstract Factory Pattern):提供一個建立一系列相關或相互依賴物件的介面,而無須指定它們具體的類。抽象工廠模式又稱為Kit模式,屬於物件建立型模式。
interface AnimalsFactory // 抽象工廠
{
public function createCat(); // 生產一尾貓
public function createDog(); // 生產一頭狗 -_-
}
abstract class Cat // 貓抽象
{
abstract function getCat();
}
class ForeignCat extends Cat // 貓具體
{
public function getCat()
{
return "外國布偶貓".PHP_EOL;
}
}
class ChineseCat extends Cat
{
public function getCat()
{
return "華夏貓".PHP_EOL;
}
}
abstract class Dog
{
abstract function getDog();
}
class ChineseDog extends Dog
{
public function getDog()
{
return "中華國犬".PHP_EOL;
}
}
class ForeignDog extends Dog
{
public function getDog()
{
return "外國哈士奇".PHP_EOL;
}
}
class CreateChineseAnimalFactory implements AnimalsFactory
{
public function createCat()
{
return new ChineseCat();
}
public function createDog()
{
return new ChineseDog();
}
}
class CreateForeignAnimalFactory implements AnimalsFactory
{
public function createCat()
{
return new ForeignCat();
}
public function createDog()
{
return new ForeignDog();
}
}
$result = new CreateForeignAnimalFactory();
$ForeignCat = $result->createCat();
echo $ForeignCat->getCat(); // 布偶貓
$ForeignDog = $result->createDog();
echo $ForeignDog->getDog(); // 哈士奇
複製程式碼
總結
區別
-
簡單工廠模式(靜態方法工廠模式) : 用來生產同一等級結構中的任意產品。(不能增加新的產品)
-
工廠模式 :用來生產同一等級結構中的固定產品。(支援增加任意產品)
-
抽象工廠 :用來生產不同產品種類的全部產品。(不能增加新的產品,支援增加產品種類)
結語
使用工廠模式的好時機並不總是顯而易見的。不要強制這樣做,只有在構建複雜系統時才需要進行大量的抽象。你只要知道什麼是抽象工廠,遲早你會發現一個真正的用例。good luck!
寫於2018年5月25日