此系列文章為清華大學(xué)出版社出版劉偉編著《Java設(shè)計(jì)模式》的學(xué)習(xí)筆記贷痪。
1 概述
工廠方法模式簡稱為工廠模式(Factory Pattern),又可稱為虛擬構(gòu)造器模式(Virtual Constructor Pattern)或多態(tài)工廠模式(Polymorphic Factory Pattern)。工廠方法模式是一種創(chuàng)建型模式扇谣,在工廠方法模式中,工廠父類負(fù)責(zé)定義創(chuàng)建產(chǎn)品對象的公共接口,而工廠子類負(fù)責(zé)生成具體的產(chǎn)品對象弹惦,這樣做的目的時(shí)將產(chǎn)品類的實(shí)例化操作延遲到工廠子類中完成,即通過工廠子類來確定究竟應(yīng)該實(shí)例化哪一個(gè)具體的產(chǎn)品類悄但。
工廠方法模式:定義一個(gè)用于創(chuàng)建對象的接口棠隐,但是讓子類決定將哪一個(gè)類實(shí)例化。工廠方法模式讓一個(gè)類的實(shí)例化延遲到其子類檐嚣。
2 結(jié)構(gòu)與實(shí)現(xiàn)
2.1 工廠方法模式結(jié)構(gòu)
抽象工廠模式包含4個(gè)角色:
- AbstractProduct(抽象產(chǎn)品):它是定義產(chǎn)品的接口助泽,是工廠方法模式所創(chuàng)建對象的超類,是具體產(chǎn)品對象的公共父類嚎京∥撕兀可以是抽象類或者接口。
- ConcreteProduct(具體產(chǎn)品):它實(shí)現(xiàn)了抽象產(chǎn)品所定義的接口鞍帝,某種類型的具體產(chǎn)品由專門的具體工廠創(chuàng)建诫睬,<span style="color:red;font-weight:900">具體工廠和具體產(chǎn)品之間一一對應(yīng)</span>。
- AbstractFactory(抽象工廠):在抽象工廠中聲明了抽象工廠方法帕涌,用于返回一個(gè)產(chǎn)品摄凡。抽象工廠是工廠方法模式的核心续徽,所有創(chuàng)建對象的工廠類都必須實(shí)現(xiàn)該接口。
- ConcreteFactory(具體工廠):它是抽象工廠類的子類亲澡,實(shí)現(xiàn)了在抽象工廠中聲明的工廠方法钦扭,并可由客戶端調(diào)用,返回一個(gè)具體產(chǎn)品類的實(shí)例床绪。
2.2 工廠方法模式舉例
一客情、背景介紹
某系統(tǒng)運(yùn)行日志記錄器(Logger)可以通過多種途徑保存系統(tǒng)的運(yùn)行日志,例如通過文件記錄或數(shù)據(jù)庫記錄癞己,用戶可以通過修改配置文件靈活地更換日志記錄方式膀斋。在設(shè)計(jì)各類日志記錄器時(shí),開發(fā)人員發(fā)現(xiàn)需要對日志記錄器時(shí)末秃,開發(fā)人員發(fā)現(xiàn)需要對日志記錄器進(jìn)行一些初始化工作概页,初始化參數(shù)地設(shè)置過程較為復(fù)雜,而且某些參數(shù)地設(shè)置有嚴(yán)格地先后次序 练慕,否則可能會發(fā)生記錄失敗惰匙。
為了更好地封裝記錄器的初始化過程并保證多種記錄器切換的靈活性,現(xiàn)使用工廠方法模式設(shè)計(jì)該系統(tǒng)(注:在Java中常用的日志記錄工具有SLF4J铃将、Log4j项鬼、GCLogViewer、Logstash等劲阎。)
二绘盟、項(xiàng)目結(jié)構(gòu)
三、抽象產(chǎn)品
public interface Logger {
public void writeLog();
}
四悯仙、具體產(chǎn)品
具體日志記錄器:數(shù)據(jù)庫日志記錄器
public class DatabaseLogger implements Logger {
@Override
public void writeLog() {
System.out.println("數(shù)據(jù)庫日志記錄");
}
}
具體日志記錄器:文件日志記錄器
public class FileLogger implements Logger {
@Override
public void writeLog() {
System.out.println("文件日志記錄");
}
}
五龄毡、抽象工廠
public interface LoggerFactory {
public Logger createLogger();
}
六、具體工廠
具體工廠:數(shù)據(jù)庫日志記錄器工廠
public class DatabaseLoggerFactory implements LoggerFactory {
@Override
public Logger createLogger() {
//連接數(shù)據(jù)庫锡垄,創(chuàng)建數(shù)據(jù)庫日志記錄對象等操作沦零,代碼省略
Logger logger = new DatabaseLogger();
//寫入日志等操作,代碼省略
return logger;
}
}
具體工廠:文件日志記錄器工廠
public class FileLoggerFactory implements LoggerFactory {
@Override
public Logger createLogger() {
//創(chuàng)建文件日志記錄器對象货岭,代碼省略
Logger logger = new FileLogger();
//創(chuàng)建文件路操,代碼省略
return logger;
}
}
七、測試Client
import CreationalPattern.FactoryMethodPattern.AbstractFactory.LoggerFactory;
import CreationalPattern.FactoryMethodPattern.AbstractProduct.Logger;
import CreationalPattern.FactoryMethodPattern.ConcreteFactory.DatabaseLoggerFactory;
import CreationalPattern.FactoryMethodPattern.ConcreteFactory.FileLoggerFactory;
public class Client {
public static void main(String[] args) {
LoggerFactory factory;
Logger logger;
/**
* note:可以引入文件讀取和反射加載機(jī)制千贯,提供一個(gè)專門的配置文件屯仗。
* note:只需要修改具體的XxxLoggerFactory是哪一個(gè)即可實(shí)現(xiàn)生產(chǎn)兩種不同的Logger
*/
factory = new FileLoggerFactory();//文件日志記錄
// factory = new DatabaseLoggerFactory();//數(shù)據(jù)庫日志記錄
logger = factory.createLogger();
logger.writeLog();
}
}
八、打印結(jié)果
我們只需要改變實(shí)現(xiàn)抽象工廠的具體工廠類型搔谴,即可創(chuàng)建不同的日志記錄器:
3 總結(jié)
工廠方法模式是簡單工廠模式的延申魁袜,它繼承了簡單工廠模式的優(yōu)點(diǎn),同時(shí)還彌補(bǔ)了簡單工廠模式的不足。工廠方法模式是使用頻率最高的設(shè)計(jì)模式之一峰弹,是很多開源框架和API類庫的核心模式距境。
3.1 工廠方法模式優(yōu)點(diǎn)
- 在工廠方法模式中,工廠方法用來創(chuàng)建客戶所需要的產(chǎn)品垮卓,同時(shí)還向客戶隱藏了哪種具體產(chǎn)品將被實(shí)例化這一細(xì)節(jié),用戶只需要關(guān)心所需產(chǎn)品對應(yīng)的工廠师幕,無需關(guān)心創(chuàng)建細(xì)節(jié)粟按,甚至無需知道具體產(chǎn)品類的類名。
- 基于工廠角色和產(chǎn)品角色的多態(tài)性設(shè)計(jì)是工廠方法模式的關(guān)鍵霹粥。它能夠 讓工廠自主確定創(chuàng)建何種產(chǎn)品對象灭将,而如何創(chuàng)建這個(gè)對象的細(xì)節(jié)完全封裝在具體工廠內(nèi)部。工廠方法模式之所以被稱為多態(tài)工廠模式后控,正式因?yàn)樗械木唧w的工廠類都具有同一抽象父類庙曙。
- 使用工廠方法模式的另一個(gè)優(yōu)點(diǎn)是在系統(tǒng)中加入新產(chǎn)品時(shí)無需修改抽象工廠和抽象產(chǎn)品提供的接口,無需修改客戶端浩淘,也無需修改其他的具體工廠和具體產(chǎn)品捌朴,而只需添加一個(gè)具體工廠和具體產(chǎn)品即可,這樣系統(tǒng)的可擴(kuò)展性也就變得非常好张抄,完全符合開閉原則砂蔽。
3.2 工廠方法模式確定
- 在添加新產(chǎn)品時(shí)需要編寫新的具體產(chǎn)品類,而且還要提供與之對應(yīng)的具體工廠類署惯,系統(tǒng)中類的個(gè)數(shù)成對增加左驾,在一定程度上增加了系統(tǒng)的復(fù)雜度,有更多的類需要編譯和運(yùn)行极谊,會給系統(tǒng)帶來額外的開銷诡右。
- 由于考慮到徐通的可擴(kuò)展性,需要引入抽象層轻猖,在客戶端代碼中均使用抽象層進(jìn)行定義帆吻,增加了系統(tǒng)的抽象性和理解難度。
3.3 工廠方法模式適用環(huán)境
- 客戶端不知道它所需要的對象的類蜕依。在工廠方法模式中桅锄,客戶端不需要知道具體產(chǎn)品類的類名,只需要知道對應(yīng)的工廠即可样眠,具體產(chǎn)品對象有具體工廠類創(chuàng)建友瘤,可將具體工廠 類的類名存儲在配置文件或數(shù)據(jù)庫中。
- 抽象工廠類通過其子類來指定創(chuàng)建哪個(gè)對象檐束。在工廠方法模式中辫秧,對于抽象工廠類只需要提供一個(gè)創(chuàng)建產(chǎn)品的接口,而由子類來確定具體要?jiǎng)?chuàng)建的對象被丧,利用面向?qū)ο蟮亩鄳B(tài)性和里氏替換原則盟戏,在程序運(yùn)行時(shí)子類對象將覆蓋父類對象绪妹,從而使得系統(tǒng)更容易擴(kuò)展。