抽象工廠
定義
抽象工廠模式的實質(zhì)是“提供接口,創(chuàng)建一系列相關(guān)或獨立的對象,而不指定這些對象的具體類。”
使用
具體的工廠決定了創(chuàng)建對象的具體類型,而且工廠就是對象實際創(chuàng)建的地方(比如在C++中,用“new”操作符創(chuàng)建對象)。然而,抽象工廠只返回一個指向創(chuàng)建的對象的抽象引用(或指針)。
這樣,客戶端程序調(diào)用抽象工廠引用的方法,由具體工廠完成對象創(chuàng)建,然后客戶端程序得到的是抽象產(chǎn)品的引用。如此使客戶端代碼與對象的創(chuàng)建分離開來。
因為工廠僅僅返回一個抽象產(chǎn)品的引用(或指針),所以客戶端程序不知道(也不會牽絆于)工廠創(chuàng)建對象的具體類型。然而,工廠知道具體對象的類型;例如,工廠可能從配置文件中讀取某種類型。這時,客戶端沒有必要指定具體類型,因為已經(jīng)在配置文件中指定了。通常,這意味著:
客戶端代碼不知道任何具體類型,也就沒必要引入任何相關(guān)的頭文件或類定義??蛻舳舜a僅僅處理抽象類型。工廠確實創(chuàng)建了具體類型的對象,但是客戶端代碼僅使用這些對象的抽象接口來訪問它們。
如果要增加一個具體類型,只需要修改客戶端代碼使用另一個工廠即可,而且這個修改通常只是一個文件中的一行代碼。不同的工廠創(chuàng)建不同的具體類型的對象,但是和以前一樣返回一個抽象類型的引用(或指針),因此客戶端代碼的其他部分不需要任何改動。這樣比修改客戶端代碼創(chuàng)建新類型的對象簡單多了。如果是后者的話,需要修改代碼中每一個創(chuàng)建這種對象的地方(而且需要注意的是,這些地方都知道對象的具體類型,而且需要引入具體類型的頭文件或類定義)。如果所有的工廠對象都存儲在全局的單例對象中,所有的客戶端代碼到這個單例中訪問需要的工廠,那么,更換工廠就非常簡單了,僅僅需要更改這個單例對象即可。
結(jié)構(gòu)
LePUS3圖
類圖
GuiFactory 接口中的 createButton 方法返回 Button 類型的對象。返回 Button 的哪種實現(xiàn)依賴于使用 GuiFactory 的哪種實現(xiàn)。
需要注意的是,為了簡潔起見,以上類圖僅僅展示了創(chuàng)建一個類型對象的工廠。而在抽象工廠模式中,通常一個工廠能夠創(chuàng)建若干種不同類型的對象。
代碼舉例
假設(shè)我們有兩種產(chǎn)品接口 Button 和 Border ,每一種產(chǎn)品都支持多種系列,比如 Mac 系列和 Windows 系列。這樣每個系列的產(chǎn)品分別是 MacButton, WinButton, MacBorder, WinBorder 。為了可以在運行時刻創(chuàng)建一個系列的產(chǎn)品族,我們可以為每個系列的產(chǎn)品族創(chuàng)建一個工廠 MacFactory 和 WinFactory 。每個工廠都有兩個方法 CreateButton 和 CreateBorder 并返回對應(yīng)的產(chǎn)品,可以將這兩個方法抽象成一個接口 AbstractFactory 。這樣在運行時刻我們可以選擇創(chuàng)建需要的產(chǎn)品系列。
C++
我們的產(chǎn)品結(jié)構(gòu)是這樣的
classButton;// Abstract ClassclassMacButton:publicButton{};classWinButton:publicButton{};classBorder;// Abstract ClassclassMacBorder:publicBorder{};classWinBorder:publicBorder{};
對應(yīng)的工廠是這樣的
classAbstractFactory{public:virtualButton*CreateButton()=0;virtualBorder*CreateBorder()=0;};classMacFactory:publicAbstractFactory{public:MacButton*CreateButton(){returnnewMacButton;}MacBorder*CreateBorder(){returnnewMacBorder;}};classWinFactory:publicAbstractFactory{public:WinButton*CreateButton(){returnnewWinButton;}WinBorder*CreateBorder(){returnnewWinBorder;}};
那么客戶可以根據(jù)需要選擇 Mac 風(fēng)格或者 Win 風(fēng)格來創(chuàng)建 Button 或 Border
AbstractFactory*fac;switch(style){caseMAC:fac=newMacFactory;break;caseWIN:fac=newWinFactory;break;}Button*button=fac->CreateButton();Border*border=fac->CreateBorder();
PHP
/*************************************************************************** * AbstractFactory.php * ------------------- * Time : 2006-11-11 * Coder : rollenc(http://www.rollenc.com) * syre(http://syre.blogbus.com) ***************************************************************************/abstractclassAbstractFactory{abstractpublicfunctionCreateButton();abstractpublicfunctionCreateBorder();}classMacFactoryextendsAbstractFactory{publicfunctionCreateButton(){returnnewMacButton();}publicfunctionCreateBorder(){returnnewMacBorder();}}classWinFactoryextendsAbstractFactory{publicfunctionCreateButton(){returnnewWinButton();}publicfunctionCreateBorder(){returnnewWinBorder();}}classButton{}classBorder{}classMacButtonextendsButton{function__construct(){echo"MacButton is created"."\n";}}classMacBorderextendsBorder{function__construct(){echo"MacBorder is created"."\n";}}classWinButtonextendsButton{function__construct(){echo"WinButton is created"."\n";}}classWinBorderextendsBorder{function__construct(){echo"WinBorder is created"."\n";}}?>
那么客戶可以根據(jù)需要選擇 Mac 風(fēng)格或者 Win 風(fēng)格的 Button 或 Border 來創(chuàng)建
$type="Mac";//value by user.if(!in_array($type,array("Win","Mac")))die("Type Error");$factoryClass=$type."Factory";$factory=new$factoryClass;$factory->CreateButton();$factory->CreateBorder();?>
Java
使用上面的例子
publicinterfaceButton{}publicinterfaceBorder{}
實現(xiàn)抽象類
publicclassMacButtonimplementsButton{}publicclassMacBorderimplementsBorder{}publicclassWinButtonimplementsButton{}publicclassWinBorderimplementsBorder{}
接著實現(xiàn)工廠
publicclassButtonFactory{publicstaticButtoncreateMacButton(){returnnewMacButton();}publicstaticButtoncreateWinButton(){returnnewWinButton();}}
publicclassBorderFactory{publicstaticBordercreateMacBorder(){returnnewMacBorder();}publicstaticBordercreateWinBorder(){returnnewWinBorder();}}
適用性
在以下情況可以考慮使用抽象工廠模式:
一個系統(tǒng)要獨立于它的產(chǎn)品的創(chuàng)建、組合和表示時。
一個系統(tǒng)要由多個產(chǎn)品系列中的一個來配置時。
需要強(qiáng)調(diào)一系列相關(guān)的產(chǎn)品對象的設(shè)計以便進(jìn)行聯(lián)合使用時。
提供一個產(chǎn)品類庫,而只想顯示它們的接口而不是實現(xiàn)時。
優(yōu)點
具體產(chǎn)品從客戶代碼中被分離出來
容易改變產(chǎn)品的系列
將一個系列的產(chǎn)品族統(tǒng)一到一起創(chuàng)建
缺點
在產(chǎn)品族中擴(kuò)展新的產(chǎn)品是很困難的,它需要修改抽象工廠的接口
參見
工廠方法模式
單例模式
設(shè)計模式 (計算機(jī))
免責(zé)聲明:以上內(nèi)容版權(quán)歸原作者所有,如有侵犯您的原創(chuàng)版權(quán)請告知,我們將盡快刪除相關(guān)內(nèi)容。感謝每一位辛勤著寫的作者,感謝每一位的分享。
- 有價值
- 一般般
- 沒價值
{{item.userName}} 舉報
{{item.time}} {{item.replyListShow ? '收起' : '展開'}}評論 {{curReplyId == item.id ? '取消回復(fù)' : '回復(fù)'}}
{{_reply.userName}} 舉報
{{_reply.time}}