簡單工廠模式雖然簡單鲫竞,但存在一個很嚴重的問題找岖。當系統(tǒng)中需要引入新產(chǎn)品時,由于靜態(tài)工廠方法通過所傳入?yún)?shù)的不同來創(chuàng)建不同的產(chǎn)品,這必定要修改工廠類的源代碼农曲,將違背“開閉原則”驰后,如何實現(xiàn)增加新產(chǎn)品而不影響已有代碼碍论?工廠方法模式應(yīng)運而生康谆,本文將介紹第二種工廠模式——工廠方法模式。
1日志記錄器的設(shè)計
Sunny軟件公司欲開發(fā)一個系統(tǒng)運行日志記錄器(Logger)映九,該記錄器可以通過多種途徑保存系統(tǒng)的運行日志梦湘,如通過文件記錄或數(shù)據(jù)庫記錄,用戶可以通過修改配置文件靈活地更換日志記錄方式件甥。在設(shè)計各類日志記錄器時捌议,Sunny公司的開發(fā)人員發(fā)現(xiàn)需要對日志記錄器進行一些初始化工作,初始化參數(shù)的設(shè)置過程較為復(fù)雜引有,而且某些參數(shù)的設(shè)置有嚴格的先后次序瓣颅,否則可能會發(fā)生記錄失敗。如何封裝記錄器的初始化過程并保證多種記錄器切換的靈活性是Sunny公司開發(fā)人員面臨的一個難題譬正。
Sunny公司的開發(fā)人員通過對該需求進行分析宫补,發(fā)現(xiàn)該日志記錄器有兩個設(shè)計要點:
(1)需要封裝日志記錄器的初始化過程檬姥,這些初始化工作較為復(fù)雜,例如需要初始化其他相關(guān)的類粉怕,還有可能需要讀取配置文件(例如連接數(shù)據(jù)庫或創(chuàng)建文件)健民,導(dǎo)致代碼較長,如果將它們都寫在構(gòu)造函數(shù)中贫贝,會導(dǎo)致構(gòu)造函數(shù)龐大秉犹,不利于代碼的修改和維護;
(2)用戶可能需要更換日志記錄方式稚晚,在客戶端代碼中需要提供一種靈活的方式來選擇日志記錄器崇堵,盡量在不修改源代碼的基礎(chǔ)上更換或者增加日志記錄方式。
Sunny公司開發(fā)人員最初使用簡單工廠模式對日志記錄器進行了設(shè)計客燕,初始結(jié)構(gòu)如圖1所示:
圖1基于簡單工廠模式設(shè)計的日志記錄器結(jié)構(gòu)圖
在圖1中鸳劳,LoggerFactory充當創(chuàng)建日志記錄器的工廠,提供了工廠方法createLogger()用于創(chuàng)建日志記錄器也搓,Logger是抽象日志記錄器接口棍辕,其子類為具體日志記錄器。其中还绘,工廠類LoggerFactory代碼片段如下所示:
[java]view plaincopy
//日志記錄器工廠
classLoggerFactory?{
//靜態(tài)工廠方法
publicstaticLogger?createLogger(String?args)?{
if(args.equalsIgnoreCase("db"))?{
//連接數(shù)據(jù)庫,代碼省略
//創(chuàng)建數(shù)據(jù)庫日志記錄器對象
Logger?logger?=newDatabaseLogger();
//初始化數(shù)據(jù)庫日志記錄器栖袋,代碼省略
returnlogger;
}
elseif(args.equalsIgnoreCase("file"))?{
//創(chuàng)建日志文件
//創(chuàng)建文件日志記錄器對象
Logger?logger?=newFileLogger();
//初始化文件日志記錄器拍顷,代碼省略
returnlogger;
}
else{
returnnull;
}
}
}
為了突出設(shè)計重點,我們對上述代碼進行了簡化塘幅,省略了具體日志記錄器類的初始化代碼昔案。在LoggerFactory類中提供了靜態(tài)工廠方法createLogger(),用于根據(jù)所傳入的參數(shù)創(chuàng)建各種不同類型的日志記錄器电媳。通過使用簡單工廠模式踏揣,我們將日志記錄器對象的創(chuàng)建和使用分離,客戶端只需使用由工廠類創(chuàng)建的日志記錄器對象即可匾乓,無須關(guān)心對象的創(chuàng)建過程捞稿,但是我們發(fā)現(xiàn),雖然簡單工廠模式實現(xiàn)了對象的創(chuàng)建和使用分離拼缝,但是仍然存在如下兩個問題:
(1)工廠類過于龐大娱局,包含了大量的if…else…代碼,導(dǎo)致維護和測試難度增大咧七;
(2)系統(tǒng)擴展不靈活衰齐,如果增加新類型的日志記錄器,必須修改靜態(tài)工廠方法的業(yè)務(wù)邏輯继阻,違反了“開閉原則”耻涛。
如何解決這兩個問題废酷,提供一種簡單工廠模式的改進方案?這就是本文所介紹的工廠方法模式的動機之一抹缕。
2 工廠方法模式概述
在簡單工廠模式中只提供一個工廠類澈蟆,該工廠類處于對產(chǎn)品類進行實例化的中心位置,它需要知道每一個產(chǎn)品對象的創(chuàng)建細節(jié)歉嗓,并決定何時實例化哪一個產(chǎn)品類丰介。簡單工廠模式最大的缺點是當有新產(chǎn)品要加入到系統(tǒng)中時,必須修改工廠類鉴分,需要在其中加入必要的業(yè)務(wù)邏輯哮幢,這違背了“開閉原則”。此外志珍,在簡單工廠模式中橙垢,所有的產(chǎn)品都由同一個工廠創(chuàng)建,工廠類職責較重伦糯,業(yè)務(wù)邏輯較為復(fù)雜柜某,具體產(chǎn)品與工廠類之間的耦合度高,嚴重影響了系統(tǒng)的靈活性和擴展性敛纲,而工廠方法模式則可以很好地解決這一問題喂击。
在工廠方法模式中,我們不再提供一個統(tǒng)一的工廠類來創(chuàng)建所有的產(chǎn)品對象淤翔,而是針對不同的產(chǎn)品提供不同的工廠翰绊,系統(tǒng)提供一個與產(chǎn)品等級結(jié)構(gòu)對應(yīng)的工廠等級結(jié)構(gòu)。工廠方法模式定義如下:
工廠方法模式(Factory Method Pattern):定義一個用于創(chuàng)建對象的接口旁壮,讓子類決定將哪一個類實例化监嗜。工廠方法模式讓一個類的實例化延遲到其子類。工廠方法模式又簡稱為工廠模式(Factory Pattern)抡谐,又可稱作虛擬構(gòu)造器模式(Virtual Constructor Pattern)或多態(tài)工廠模式(Polymorphic Factory Pattern)裁奇。工廠方法模式是一種類創(chuàng)建型模式。
工廠方法模式提供一個抽象工廠接口來聲明抽象工廠方法麦撵,而由其子類來具體實現(xiàn)工廠方法刽肠,創(chuàng)建具體的產(chǎn)品對象。工廠方法模式結(jié)構(gòu)如圖2所示:
圖2工廠方法模式結(jié)構(gòu)圖
在工廠方法模式結(jié)構(gòu)圖中包含如下幾個角色:
●Product(抽象產(chǎn)品):它是定義產(chǎn)品的接口免胃,是工廠方法模式所創(chuàng)建對象的超類型五垮,也就是產(chǎn)品對象的公共父類。
●ConcreteProduct(具體產(chǎn)品):它實現(xiàn)了抽象產(chǎn)品接口杜秸,某種類型的具體產(chǎn)品由專門的具體工廠創(chuàng)建放仗,具體工廠和具體產(chǎn)品之間一一對應(yīng)。
●Factory(抽象工廠):在抽象工廠類中撬碟,聲明了工廠方法(Factory Method)诞挨,用于返回一個產(chǎn)品莉撇。抽象工廠是工廠方法模式的核心,所有創(chuàng)建對象的工廠類都必須實現(xiàn)該接口惶傻。
●ConcreteFactory(具體工廠):它是抽象工廠類的子類棍郎,實現(xiàn)了抽象工廠中定義的工廠方法,并可由客戶端調(diào)用银室,返回一個具體產(chǎn)品類的實例涂佃。
與簡單工廠模式相比,工廠方法模式最重要的區(qū)別是引入了抽象工廠角色蜈敢,抽象工廠可以是接口辜荠,也可以是抽象類或者具體類,其典型代碼如下所示:
[java]view plaincopy
interfaceFactory?{
publicProduct?factoryMethod();
}
在抽象工廠中聲明了工廠方法但并未實現(xiàn)工廠方法抓狭,具體產(chǎn)品對象的創(chuàng)建由其子類負責伯病,客戶端針對抽象工廠編程,可在運行時再指定具體工廠類否过,具體工廠類實現(xiàn)了工廠方法午笛,不同的具體工廠可以創(chuàng)建不同的具體產(chǎn)品,其典型代碼如下所示:
[java]view plaincopy
classConcreteFactoryimplementsFactory?{
publicProduct?factoryMethod()?{
returnnewConcreteProduct();
}
}
在實際使用時苗桂,具體工廠類在實現(xiàn)工廠方法時除了創(chuàng)建具體產(chǎn)品對象之外药磺,還可以負責產(chǎn)品對象的初始化工作以及一些資源和環(huán)境配置工作,例如連接數(shù)據(jù)庫煤伟、創(chuàng)建文件等与涡。
在客戶端代碼中,只需關(guān)心工廠類即可持偏,不同的具體工廠可以創(chuàng)建不同的產(chǎn)品,典型的客戶端類代碼片段如下所示:
[java]view plaincopy
……
Factory?factory;
factory?=newConcreteFactory();//可通過配置文件實現(xiàn)
Product?product;
product?=?factory.factoryMethod();
……
可以通過配置文件來存儲具體工廠類ConcreteFactory的類名氨肌,更換新的具體工廠時無須修改源代碼鸿秆,系統(tǒng)擴展更為方便。
3完整解決方案
Sunny公司開發(fā)人員決定使用工廠方法模式來設(shè)計日志記錄器怎囚,其基本結(jié)構(gòu)如圖3所示:
圖3日志記錄器結(jié)構(gòu)圖
在圖3中卿叽,Logger接口充當抽象產(chǎn)品,其子類FileLogger和DatabaseLogger充當具體產(chǎn)品恳守,LoggerFactory接口充當抽象工廠考婴,其子類FileLoggerFactory和DatabaseLoggerFactory充當具體工廠。完整代碼如下所示:
[java]view plaincopy
//日志記錄器接口:抽象產(chǎn)品
interfaceLogger?{
publicvoidwriteLog();
}
//數(shù)據(jù)庫日志記錄器:具體產(chǎn)品
classDatabaseLoggerimplementsLogger?{
publicvoidwriteLog()?{
System.out.println("數(shù)據(jù)庫日志記錄催烘。");
}
}
//文件日志記錄器:具體產(chǎn)品
classFileLoggerimplementsLogger?{
publicvoidwriteLog()?{
System.out.println("文件日志記錄沥阱。");
}
}
//日志記錄器工廠接口:抽象工廠
interfaceLoggerFactory?{
publicLogger?createLogger();
}
//數(shù)據(jù)庫日志記錄器工廠類:具體工廠
classDatabaseLoggerFactoryimplementsLoggerFactory?{
publicLogger?createLogger()?{
//連接數(shù)據(jù)庫,代碼省略
//創(chuàng)建數(shù)據(jù)庫日志記錄器對象
Logger?logger?=newDatabaseLogger();
//初始化數(shù)據(jù)庫日志記錄器伊群,代碼省略
returnlogger;
}
}
//文件日志記錄器工廠類:具體工廠
classFileLoggerFactoryimplementsLoggerFactory?{
publicLogger?createLogger()?{
//創(chuàng)建文件日志記錄器對象
Logger?logger?=newFileLogger();
//創(chuàng)建文件考杉,代碼省略
returnlogger;
}
}
編寫如下客戶端測試代碼:
[java]view plaincopy
classClient?{
publicstaticvoidmain(String?args[])?{
LoggerFactory?factory;
Logger?logger;
factory?=newFileLoggerFactory();//可引入配置文件實現(xiàn)
logger?=?factory.createLogger();
logger.writeLog();
}
}
編譯并運行程序策精,輸出結(jié)果如下:
文件日志記錄。
4 反射與配置文件
為了讓系統(tǒng)具有更好的靈活性和可擴展性崇棠,Sunny公司開發(fā)人員決定對日志記錄器客戶端代碼進行重構(gòu)咽袜,使得可以在不修改任何客戶端代碼的基礎(chǔ)上更換或增加新的日志記錄方式。
在客戶端代碼中將不再使用new關(guān)鍵字來創(chuàng)建工廠對象枕稀,而是將具體工廠類的類名存儲在配置文件(如XML文件)中询刹,通過讀取配置文件獲取類名字符串,再使用Java的反射機制萎坷,根據(jù)類名字符串生成對象凹联。在整個實現(xiàn)過程中需要用到兩個技術(shù):Java反射機制與配置文件讀取。軟件系統(tǒng)的配置文件通常為XML文件食铐,我們可以使用DOM (Document Object Model)匕垫、SAX (Simple API for XML)、StAX (Streaming API for XML)等技術(shù)來處理XML文件虐呻。關(guān)于DOM象泵、SAX、StAX等技術(shù)的詳細學習大家可以參考其他相關(guān)資料斟叼,在此不予擴展偶惠。
擴展
關(guān)于Java與XML的相關(guān)資料,大家可以閱讀Tom Myers和Alexander Nakhimovsky所著的《JavaXML編程指南》一書或訪問developer Works中國中的“javaXML技術(shù)專題”朗涩,參考鏈接:
http://www.ibm.com/developerworks/cn/xml/theme/x-java.html
Java反射(Java Reflection)是指在程序運行時獲取已知名稱的類或已有對象的相關(guān)信息的一種機制忽孽,包括類的方法、屬性谢床、父類等信息兄一,還包括實例的創(chuàng)建和實例類型的判斷等。在反射中使用最多的類是Class识腿,Class類的實例表示正在運行的Java應(yīng)用程序中的類和接口出革,其forName(String className)方法可以返回與帶有給定字符串名的類或接口相關(guān)聯(lián)的Class對象,再通過Class對象的newInstance()方法創(chuàng)建此對象所表示的類的一個新實例渡讼,即通過一個類名字符串得到類的實例骂束。如創(chuàng)建一個字符串類型的對象,其代碼如下:
[java]view plaincopy
//通過類名生成實例對象并將其返回
Class?c=Class.forName("String");
Object?obj=c.newInstance();
returnobj;
此外成箫,在JDK中還提供了java.lang.reflect包展箱,封裝了其他與反射相關(guān)的類,此處只用到上述簡單的反射代碼蹬昌,在此不予擴展混驰。
Sunny公司開發(fā)人員創(chuàng)建了如下XML格式的配置文件config.xml用于存儲具體日志記錄器工廠類類名:
[html]view plaincopy
FileLoggerFactory
為了讀取該配置文件并通過存儲在其中的類名字符串反射生成對象,Sunny公司開發(fā)人員開發(fā)了一個名為XMLUtil的工具類,其詳細代碼如下所示:
[java]view plaincopy
//工具類XMLUtil.java
importjavax.xml.parsers.*;
importorg.w3c.dom.*;
importorg.xml.sax.SAXException;
importjava.io.*;
publicclassXMLUtil?{
//該方法用于從XML配置文件中提取具體類類名账胧,并返回一個實例對象
publicstaticObject?getBean()?{
try{
//創(chuàng)建DOM文檔對象
DocumentBuilderFactory?dFactory?=?DocumentBuilderFactory.newInstance();
DocumentBuilder?builder?=?dFactory.newDocumentBuilder();
Document?doc;
doc?=?builder.parse(newFile("config.xml"));
//獲取包含類名的文本節(jié)點
NodeList?nl?=?doc.getElementsByTagName("className");
Node?classNode=nl.item(0).getFirstChild();
String?cName=classNode.getNodeValue();
//通過類名生成實例對象并將其返回
Class?c=Class.forName(cName);
Object?obj=c.newInstance();
returnobj;
}
catch(Exception?e)?{
e.printStackTrace();
returnnull;
}
}
}
有了XMLUtil類后竞慢,可以對日志記錄器的客戶端代碼進行修改,不再直接使用new關(guān)鍵字來創(chuàng)建具體的工廠類治泥,而是將具體工廠類的類名存儲在XML文件中筹煮,再通過XMLUtil類的靜態(tài)工廠方法getBean()方法進行對象的實例化,代碼修改如下:
[java]view plaincopy
classClient?{
publicstaticvoidmain(String?args[])?{
LoggerFactory?factory;
Logger?logger;
factory?=?(LoggerFactory)XMLUtil.getBean();//getBean()的返回類型為Object居夹,需要進行強制類型轉(zhuǎn)換
logger?=?factory.createLogger();
logger.writeLog();
}
}
引入XMLUtil類和XML配置文件后败潦,如果要增加新的日志記錄方式,只需要執(zhí)行如下幾個步驟:
(1)新的日志記錄器需要繼承抽象日志記錄器Logger准脂;
(2)對應(yīng)增加一個新的具體日志記錄器工廠劫扒,繼承抽象日志記錄器工廠LoggerFactory,并實現(xiàn)其中的工廠方法createLogger()狸膏,設(shè)置好初始化參數(shù)和環(huán)境變量沟饥,返回具體日志記錄器對象;
(3)修改配置文件config.xml湾戳,將新增的具體日志記錄器工廠類的類名字符串替換原有工廠類類名字符串贤旷;
(4)編譯新增的具體日志記錄器類和具體日志記錄器工廠類,運行客戶端測試類即可使用新的日志記錄方式砾脑,而原有類庫代碼無須做任何修改幼驶,完全符合“開閉原則”。
通過上述重構(gòu)可以使得系統(tǒng)更加靈活韧衣,由于很多設(shè)計模式都關(guān)注系統(tǒng)的可擴展性和靈活性盅藻,因此都定義了抽象層,在抽象層中聲明業(yè)務(wù)方法畅铭,而將業(yè)務(wù)方法的實現(xiàn)放在實現(xiàn)層中氏淑。
5重載的工廠方法
Sunny公司開發(fā)人員通過進一步分析,發(fā)現(xiàn)可以通過多種方式來初始化日志記錄器硕噩,例如可以為各種日志記錄器提供默認實現(xiàn)假残;還可以為數(shù)據(jù)庫日志記錄器提供數(shù)據(jù)庫連接字符串,為文件日志記錄器提供文件路徑榴徐;也可以將參數(shù)封裝在一個Object類型的對象中,通過Object對象將配置參數(shù)傳入工廠類匀归。此時坑资,可以提供一組重載的工廠方法,以不同的方式對產(chǎn)品對象進行創(chuàng)建穆端。當然袱贮,對于同一個具體工廠而言,無論使用哪個工廠方法体啰,創(chuàng)建的產(chǎn)品類型均要相同攒巍。如圖4所示:
圖4重載的工廠方法結(jié)構(gòu)圖
引入重載方法后嗽仪,抽象工廠LoggerFactory的代碼修改如下:
[java]view plaincopy
interfaceLoggerFactory?{
publicLogger?createLogger();
publicLogger?createLogger(String?args);
publicLogger?createLogger(Object?obj);
}
具體工廠類DatabaseLoggerFactory代碼修改如下:
[java]view plaincopy
classDatabaseLoggerFactoryimplementsLoggerFactory?{
publicLogger?createLogger()?{
//使用默認方式連接數(shù)據(jù)庫,代碼省略
Logger?logger?=newDatabaseLogger();
//初始化數(shù)據(jù)庫日志記錄器柒莉,代碼省略
returnlogger;
}
publicLogger?createLogger(String?args)?{
//使用參數(shù)args作為連接字符串來連接數(shù)據(jù)庫闻坚,代碼省略
Logger?logger?=newDatabaseLogger();
//初始化數(shù)據(jù)庫日志記錄器,代碼省略
returnlogger;
}
publicLogger?createLogger(Object?obj)?{
//使用封裝在參數(shù)obj中的連接字符串來連接數(shù)據(jù)庫兢孝,代碼省略
Logger?logger?=newDatabaseLogger();
//使用封裝在參數(shù)obj中的數(shù)據(jù)來初始化數(shù)據(jù)庫日志記錄器窿凤,代碼省略
returnlogger;
}
}
//其他具體工廠類代碼省略
在抽象工廠中定義多個重載的工廠方法,在具體工廠中實現(xiàn)了這些工廠方法跨蟹,這些方法可以包含不同的業(yè)務(wù)邏輯雳殊,以滿足對不同產(chǎn)品對象的需求。
6工廠方法的隱藏
有時候窗轩,為了進一步簡化客戶端的使用夯秃,還可以對客戶端隱藏工廠方法,此時痢艺,在工廠類中將直接調(diào)用產(chǎn)品類的業(yè)務(wù)方法仓洼,客戶端無須調(diào)用工廠方法創(chuàng)建產(chǎn)品,直接通過工廠即可使用所創(chuàng)建的對象中的業(yè)務(wù)方法腹备。
如果對客戶端隱藏工廠方法衬潦,日志記錄器的結(jié)構(gòu)圖將修改為圖5所示:
圖5隱藏工廠方法后的日志記錄器結(jié)構(gòu)圖
在圖5中,抽象工廠類LoggerFactory的代碼修改如下:
[java]view plaincopy
//改為抽象類
abstractclassLoggerFactory?{
//在工廠類中直接調(diào)用日志記錄器類的業(yè)務(wù)方法writeLog()
publicvoidwriteLog()?{
Logger?logger?=this.createLogger();
logger.writeLog();
}
publicabstractLogger?createLogger();
}
客戶端代碼修改如下:
[java]view plaincopy
classClient?{
publicstaticvoidmain(String?args[])?{
LoggerFactory?factory;
factory?=?(LoggerFactory)XMLUtil.getBean();
factory.writeLog();//直接使用工廠對象來調(diào)用產(chǎn)品對象的業(yè)務(wù)方法
}
}
通過將業(yè)務(wù)方法的調(diào)用移入工廠類植酥,可以直接使用工廠對象來調(diào)用產(chǎn)品對象的業(yè)務(wù)方法镀岛,客戶端無須直接使用工廠方法,在某些情況下我們也可以使用這種設(shè)計方案友驮。
工廠方法模式是簡單工廠模式的延伸漂羊,它繼承了簡單工廠模式的優(yōu)點,同時還彌補了簡單工廠模式的不足卸留。工廠方法模式是使用頻率最高的設(shè)計模式之一走越,是很多開源框架和API類庫的核心模式。
1.主要優(yōu)點
工廠方法模式的主要優(yōu)點如下:
(1)在工廠方法模式中耻瑟,工廠方法用來創(chuàng)建客戶所需要的產(chǎn)品旨指,同時還向客戶隱藏了哪種具體產(chǎn)品類將被實例化這一細節(jié),用戶只需要關(guān)心所需產(chǎn)品對應(yīng)的工廠喳整,無須關(guān)心創(chuàng)建細節(jié)谆构,甚至無須知道具體產(chǎn)品類的類名。
(2)基于工廠角色和產(chǎn)品角色的多態(tài)性設(shè)計是工廠方法模式的關(guān)鍵框都。它能夠讓工廠可以自主確定創(chuàng)建何種產(chǎn)品對象搬素,而如何創(chuàng)建這個對象的細節(jié)則完全封裝在具體工廠內(nèi)部。工廠方法模式之所以又被稱為多態(tài)工廠模式,就正是因為所有的具體工廠類都具有同一抽象父類熬尺。
(3)使用工廠方法模式的另一個優(yōu)點是在系統(tǒng)中加入新產(chǎn)品時摸屠,無須修改抽象工廠和抽象產(chǎn)品提供的接口,無須修改客戶端粱哼,也無須修改其他的具體工廠和具體產(chǎn)品季二,而只要添加一個具體工廠和具體產(chǎn)品就可以了,這樣皂吮,系統(tǒng)的可擴展性也就變得非常好戒傻,完全符合“開閉原則”。
2.主要缺點
工廠方法模式的主要缺點如下:
(1)在添加新產(chǎn)品時蜂筹,需要編寫新的具體產(chǎn)品類需纳,而且還要提供與之對應(yīng)的具體工廠類,系統(tǒng)中類的個數(shù)將成對增加艺挪,在一定程度上增加了系統(tǒng)的復(fù)雜度不翩,有更多的類需要編譯和運行,會給系統(tǒng)帶來一些額外的開銷麻裳。
(2)由于考慮到系統(tǒng)的可擴展性口蝠,需要引入抽象層,在客戶端代碼中均使用抽象層進行定義津坑,增加了系統(tǒng)的抽象性和理解難度妙蔗,且在實現(xiàn)時可能需要用到DOM、反射等技術(shù)疆瑰,增加了系統(tǒng)的實現(xiàn)難度眉反。
3.適用場景
在以下情況下可以考慮使用工廠方法模式:
(1)客戶端不知道它所需要的對象的類。在工廠方法模式中穆役,客戶端不需要知道具體產(chǎn)品類的類名寸五,只需要知道所對應(yīng)的工廠即可,具體的產(chǎn)品對象由具體工廠類創(chuàng)建耿币,可將具體工廠類的類名存儲在配置文件或數(shù)據(jù)庫中梳杏。
(2)抽象工廠類通過其子類來指定創(chuàng)建哪個對象。在工廠方法模式中淹接,對于抽象工廠類只需要提供一個創(chuàng)建產(chǎn)品的接口十性,而由其子類來確定具體要創(chuàng)建的對象,利用面向?qū)ο蟮亩鄳B(tài)性和里氏代換原則塑悼,在程序運行時劲适,子類對象將覆蓋父類對象,從而使得系統(tǒng)更容易擴展拢肆。