一奕锌、簡介
工廠方法模式(Factory Method Pattern)又稱為 工廠模式,也叫虛擬構(gòu)造器(Virtual Constructor)模式或者多態(tài)工廠(Polymorphic Factory)模式,它屬于類創(chuàng)建型模式桦他。在工廠方法模式中茬暇,工廠父類負責定義創(chuàng)建產(chǎn)品對象的公共接口,而工廠子類則負責生成具體的產(chǎn)品對象敢课,這樣做的目的是將產(chǎn)品類的實例化操作延遲到工廠子類中完成阶祭,即通過工廠子類來確定究竟應該實例化哪一個具體產(chǎn)品類。為系統(tǒng)結(jié)構(gòu)提供靈活的動態(tài)擴展機制直秆,減少了耦合濒募。
根據(jù)抽象程度的不同,工廠模式可化分為三種:
- 簡單工廠模式
- 工廠方法模式
- 抽象工廠模式
二圾结、原理
在簡單工廠模式中只提供一個工廠類瑰剃,該工廠類處于對產(chǎn)品類進行實例化的中心位置,它需要知道每一個產(chǎn)品對象的創(chuàng)建細節(jié)筝野,并決定何時實例化哪一個產(chǎn)品類晌姚。簡單工廠模式最大的缺點是當有新產(chǎn)品要加入到系統(tǒng)中時,必須修改工廠類遗座,需要在其中加入必要的業(yè)務(wù)邏輯舀凛,這違背了“開閉原則”。此外途蒋,在簡單工廠模式中猛遍,所有的產(chǎn)品都由同一個工廠創(chuàng)建,工廠類職責較重号坡,業(yè)務(wù)邏輯較為復雜懊烤,具體產(chǎn)品與工廠類之間的耦合度高,嚴重影響了系統(tǒng)的靈活性和擴展性宽堆,而工廠方法模式則可以很好地解決這一問題腌紧。
在工廠方法模式中,我們不再提供一個統(tǒng)一的工廠類來創(chuàng)建所有的產(chǎn)品對象畜隶,而是針對不同的產(chǎn)品提供不同的工廠壁肋,系統(tǒng)提供一個與產(chǎn)品等級結(jié)構(gòu)對應的工廠等級結(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所示:
三、類結(jié)構(gòu)
工廠方法模式定義一個用于創(chuàng)建對象的接口郑藏,讓子類決定哪個類實例化衡查。 他可以解決簡單工廠模式中的封閉開放原則問題。
與簡單工廠模式相比必盖,工廠方法模式最重要的區(qū)別是引入了抽象工廠角色峡捡,抽象工廠可以是接口,也可以是抽象類或者具體類筑悴。
結(jié)構(gòu)如下:
角色 | 類別 | 簡述 |
---|---|---|
Product | 產(chǎn)品類 | 一般是一個抽象類或是接口 |
ConcreteProduct | 具體的產(chǎn)品類 | 實現(xiàn)或是繼承 Product |
Factory | 工廠類 | 抽象工廠 |
ConcreteFactory | 具體的工廠類 | 實現(xiàn)或是繼承Factory |
- Product(抽象產(chǎn)品):它是定義產(chǎn)品的接口们拙,是工廠方法模式所創(chuàng)建對象的超類型,也就是產(chǎn)品對象的公共父類阁吝。
- ConcreteProduct(具體產(chǎn)品):它實現(xiàn)了抽象產(chǎn)品接口砚婆,某種類型的具體產(chǎn)品由專門的具體工廠創(chuàng)建,具體工廠和具體產(chǎn)品之間一一對應突勇。
- Factory(抽象工廠):在抽象工廠類中装盯,聲明了工廠方法(Factory Method),用于返回一個產(chǎn)品甲馋。抽象工廠是工廠方法模式的核心埂奈,所有創(chuàng)建對象的工廠類都必須實現(xiàn)該接口。
- ConcreteFactory(具體工廠):它是抽象工廠類的子類定躏,實現(xiàn)了抽象工廠中定義的工廠方法账磺,并可由客戶端調(diào)用,返回一個具體產(chǎn)品類的實例痊远。
四垮抗、UML圖
五、代碼分析
比如碧聪,我們需要設(shè)計一個日志記錄器:
1冒版、抽象產(chǎn)品類
//日志記錄器接口:抽象產(chǎn)品
interface Logger {
public function writeLog();
}
2、具體產(chǎn)品類
//1)數(shù)據(jù)庫日志記錄器:具體產(chǎn)品
class DatabaseLogger implements Logger {
public function writeLog() {
echo "數(shù)據(jù)庫日志記錄逞姿。";
}
}
//2)文件日志記錄器:具體產(chǎn)品
class FileLogger implements Logger {
public function writeLog() {
echo "文件日志記錄辞嗡。";
}
}
3捆等、抽象工廠類
//日志記錄器工廠接口:抽象工廠
interface LoggerFactory {
public function createLogger();
}
4、具體工廠類
在實際使用時续室,具體工廠類在實現(xiàn)工廠方法時除了創(chuàng)建具體產(chǎn)品對象之外楚里,還可以負責產(chǎn)品對象的初始化工作以及一些資源和環(huán)境配置工作,例如連接數(shù)據(jù)庫猎贴、創(chuàng)建文件等。
//1)數(shù)據(jù)庫日志記錄器工廠類:具體工廠
class DatabaseLoggerFactory implements LoggerFactory {
public function createLogger() {
//連接數(shù)據(jù)庫蝴光,代碼省略
//創(chuàng)建數(shù)據(jù)庫日志記錄器對象
$logger = new DatabaseLogger();
//初始化數(shù)據(jù)庫日志記錄器她渴,代碼省略
return $logger;
}
}
//2)文件日志記錄器工廠類:具體工廠
class FileLoggerFactory implements LoggerFactory {
public function createLogger() {
//創(chuàng)建文件日志記錄器對象
$logger = new FileLogger();
//創(chuàng)建文件,代碼省略
return $logger;
}
}
5蔑祟、例子
$file_factory = new FileLoggerFactory(); //可引入配置文件實現(xiàn)
$file_logger = factory->createLogger();
$file_logger->writeLog();
$db_lfactory = new DatabaseLoggerFactory(); //可引入配置文件實現(xiàn)
$db_logger = factory->createLogger();
$db_logger->writeLog();
輸出結(jié)果如下:
文件日志記錄趁耗。
數(shù)據(jù)庫日志記錄。
六疆虚、特點
工廠方法模式是簡單工廠模式的延伸苛败,它繼承了簡單工廠模式的優(yōu)點,同時還彌補了簡單工廠模式的不足径簿。工廠方法模式是使用頻率最高的設(shè)計模式之一罢屈,是很多開源框架和API類庫的核心模式。
1篇亭、 優(yōu)點
- 在工廠方法模式中缠捌,工廠方法用來創(chuàng)建客戶所需要的產(chǎn)品,同時還向客戶隱藏了哪種具體產(chǎn)品類將被實例化這一細節(jié)译蒂,用戶只需要關(guān)心所需產(chǎn)品對應的工廠曼月,無須關(guān)心創(chuàng)建細節(jié),甚至無須知道具體產(chǎn)品類的類名柔昼。
- 基于工廠角色和產(chǎn)品角色的多態(tài)性設(shè)計是工廠方法模式的關(guān)鍵哑芹。它能夠讓工廠可以自主確定創(chuàng)建各種產(chǎn)品對象,而如何創(chuàng)建這個對象的細節(jié)則完全封裝在具體工廠內(nèi)部捕透。工廠方法模式之所以又被稱為多態(tài)工廠模式聪姿,就正是因為所有的具體工廠類都具有同一抽象父類。
- 使用工廠方法模式的另一個優(yōu)點是在系統(tǒng)中加入新產(chǎn)品時乙嘀,無須修改抽象工廠和抽象產(chǎn)品提供的接口咳燕,無須修改客戶端,也無須修改其他的具體工廠和具體產(chǎn)品乒躺,而只要添加一個具體工廠和具體產(chǎn)品就可以了招盲,這樣,系統(tǒng)的可擴展性也就變得非常好嘉冒,完全符合“開閉原則”曹货。
2咆繁、 缺點
- 在添加新產(chǎn)品時,需要編寫新的具體產(chǎn)品類顶籽,而且還要提供與之對應的具體工廠類玩般,系統(tǒng)中類的個數(shù)將成對增加,在一定程度上增加了系統(tǒng)的復雜度礼饱,有更多的類需要編譯和運行坏为,會給系統(tǒng)帶來一些額外的開銷。
- 由于考慮到系統(tǒng)的可擴展性镊绪,需要引入抽象層匀伏,在客戶端代碼中均使用抽象層進行定義,增加了系統(tǒng)的抽象性和理解難度蝴韭,且在實現(xiàn)時可能需要用到DOM够颠、反射等技術(shù),增加了系統(tǒng)的實現(xiàn)難度榄鉴。
3履磨、 適用場景
滿足以下條件時,可以考慮使用工廠模式方法:
- 一個類不知道它所需要的對象的類:在工廠方法模式中庆尘,客戶端不需要知道具體產(chǎn)品類的類名剃诅,只需要知道所對應的工廠即可,具體的產(chǎn)品對象由具體工廠類創(chuàng)建驶忌;客戶端需要知道創(chuàng)建具體產(chǎn)品的工廠類综苔。
- 一個類通過其子類來指定創(chuàng)建哪個對象:在工廠方法模式中,對于抽象工廠類只需要提供一個創(chuàng)建產(chǎn)品的接口位岔,而由其子類來確定具體要創(chuàng)建的對象如筛,利用面向?qū)ο蟮亩鄳B(tài)性和里氏代換原則,在程序運行時抒抬,子類對象將覆蓋父類對象杨刨,從而使得系統(tǒng)更容易擴展。
- 將創(chuàng)建對象的任務(wù)委托給多個工廠子類中的某一個擦剑,客戶端在使用時可以無須關(guān)心是哪一個工廠子類創(chuàng)建產(chǎn)品子類妖胀,需要時再動態(tài)指定,可將具體工廠類的類名存儲在配置文件或數(shù)據(jù)庫中惠勒。