原創(chuàng)文章,轉(zhuǎn)載請(qǐng)務(wù)必將下面這段話(huà)置于文章開(kāi)頭處。
本文轉(zhuǎn)發(fā)自Jason's Blog,原文鏈接
http://www.jasongj.com/design_pattern/factory_method/
工廠(chǎng)方法模式解決的問(wèn)題
上文《簡(jiǎn)單工廠(chǎng)模式不簡(jiǎn)單》中提到,簡(jiǎn)單工廠(chǎng)模式有如下缺點(diǎn),而工廠(chǎng)方法模式可以解決這些問(wèn)題
- 由于工廠(chǎng)類(lèi)集中了所有實(shí)例的創(chuàng)建邏輯,這就直接導(dǎo)致一旦這個(gè)工廠(chǎng)出了問(wèn)題,所有的客戶(hù)端都會(huì)受到牽連。
- 由于簡(jiǎn)單工廠(chǎng)模式的產(chǎn)品是基于一個(gè)共同的抽象類(lèi)或者接口,這樣一來(lái),產(chǎn)品的種類(lèi)增加的時(shí)候,即有不同的產(chǎn)品接口或者抽象類(lèi)的時(shí)候,工廠(chǎng)類(lèi)就需要判斷何時(shí)創(chuàng)建何種接口的產(chǎn)品,這就和創(chuàng)建何種種類(lèi)的產(chǎn)品相互混淆在了一起,違背了單一職責(zé)原則,導(dǎo)致系統(tǒng)喪失靈活性和可維護(hù)性。
- 簡(jiǎn)單工廠(chǎng)模式違背了“開(kāi)放-關(guān)閉原則”,因?yàn)楫?dāng)我們新增加一個(gè)產(chǎn)品的時(shí)候必須修改工廠(chǎng)類(lèi),相應(yīng)的工廠(chǎng)類(lèi)就需要重新編譯一遍。
- 簡(jiǎn)單工廠(chǎng)模式由于使用了靜態(tài)工廠(chǎng)方法,造成工廠(chǎng)角色無(wú)法形成基于繼承的等級(jí)結(jié)構(gòu)。
工廠(chǎng)方法模式
工廠(chǎng)方法模式介紹
工廠(chǎng)方法模式(Factory Method Pattern)又稱(chēng)為工廠(chǎng)模式,也叫多態(tài)工廠(chǎng)模式或者虛擬構(gòu)造器模式。在工廠(chǎng)方法模式中,工廠(chǎng)父類(lèi)定義創(chuàng)建產(chǎn)品對(duì)象的公共接口,具體的工廠(chǎng)子類(lèi)負(fù)責(zé)創(chuàng)建具體的產(chǎn)品對(duì)象。每一個(gè)工廠(chǎng)子類(lèi)負(fù)責(zé)創(chuàng)建一種具體產(chǎn)品。
工廠(chǎng)方法模式類(lèi)圖
工廠(chǎng)模式類(lèi)圖如下 (點(diǎn)擊可查看大圖)

工廠(chǎng)方法模式角色劃分
- 抽象產(chǎn)品(或者產(chǎn)品接口),如上圖中IUserDao
- 具體產(chǎn)品,如上圖中的MySQLUserDao,PostgreSQLUserDao和OracleUserDao
- 抽象工廠(chǎng)(或者工廠(chǎng)接口),如IFactory
- 具體工廠(chǎng),如MySQLFactory,PostgreSQLFactory和OracleFactory
工廠(chǎng)方法模式使用方式
如簡(jiǎn)單工廠(chǎng)模式直接使用靜態(tài)工廠(chǎng)方法創(chuàng)建產(chǎn)品對(duì)象不同,在工廠(chǎng)方法,客戶(hù)端通過(guò)實(shí)例化具體的工廠(chǎng)類(lèi),并調(diào)用其創(chuàng)建實(shí)例接口創(chuàng)建具體產(chǎn)品類(lèi)的實(shí)例。根據(jù)依賴(lài)倒置原則,具體工廠(chǎng)類(lèi)的實(shí)例由工廠(chǎng)接口引用(客戶(hù)端依賴(lài)于抽象工廠(chǎng)而非具體工廠(chǎng)),具體產(chǎn)品的實(shí)例由產(chǎn)品接口引用(客戶(hù)端和工廠(chǎng)依賴(lài)于抽象產(chǎn)品而非具體產(chǎn)品)。具體調(diào)用代碼如下
package com.jasongj.client;
import com.jasongj.dao.IUserDao;
import com.jasongj.factory.IDaoFactory;
import com.jasongj.factory.MySQLDaoFactory;
public class Client {
public static void main(String[] args) {
IDaoFactory factory = new MySQLDaoFactory();
IUserDao userDao = factory.createUserDao();
userDao.getUser("admin");
}
}
工廠(chǎng)方法模式示例代碼
本文所述工廠(chǎng)方法模式示例代碼可從作者Github下載
工廠(chǎng)方法模式優(yōu)點(diǎn)
- 因?yàn)槊總€(gè)具體工廠(chǎng)類(lèi)只負(fù)責(zé)創(chuàng)建產(chǎn)品,沒(méi)有簡(jiǎn)單工廠(chǎng)中的邏輯判斷,因此符合單一職責(zé)原則。
- 與簡(jiǎn)單工廠(chǎng)模式不同,工廠(chǎng)方法并不使用靜態(tài)工廠(chǎng)方法,可以形成基于繼承的等級(jí)結(jié)構(gòu)。
- 新增一種產(chǎn)品時(shí),只需要增加相應(yīng)的具體產(chǎn)品類(lèi)和相應(yīng)的工廠(chǎng)子類(lèi)即可,相比于簡(jiǎn)單工廠(chǎng)模式需要修改判斷邏輯而言,工廠(chǎng)方法模式更符合開(kāi)-閉原則。
工廠(chǎng)方法模式缺點(diǎn)
- 添加新產(chǎn)品時(shí),除了增加新產(chǎn)品類(lèi)外,還要提供與之對(duì)應(yīng)的具體工廠(chǎng)類(lèi),系統(tǒng)類(lèi)的個(gè)數(shù)將成對(duì)增加,在一定程度上增加了系統(tǒng)的復(fù)雜度,有更多的類(lèi)需要編譯和運(yùn)行,會(huì)給系統(tǒng)帶來(lái)一些額外的開(kāi)銷(xiāo)。
- 雖然保證了工廠(chǎng)方法內(nèi)的對(duì)修改關(guān)閉,但對(duì)于使用工廠(chǎng)方法的類(lèi),如果要換用另外一種產(chǎn)品,仍然需要修改實(shí)例化的具體工廠(chǎng)。
- 一個(gè)具體工廠(chǎng)只能創(chuàng)建一種具體產(chǎn)品
簡(jiǎn)單工廠(chǎng)模式與OOP原則
已遵循的原則
- 依賴(lài)倒置原則
- 迪米特法則
- 里氏替換原則
- 接口隔離原則
- 單一職責(zé)原則(每個(gè)工廠(chǎng)只負(fù)責(zé)創(chuàng)建自己的具體產(chǎn)品,沒(méi)有簡(jiǎn)單工廠(chǎng)中的邏輯判斷)
- 開(kāi)閉原則(增加新的產(chǎn)品,不像簡(jiǎn)單工廠(chǎng)那樣需要修改已有的工廠(chǎng),而只需增加相應(yīng)的具體工廠(chǎng)類(lèi))
未遵循的原則
- 開(kāi)閉原則(雖然工廠(chǎng)對(duì)修改關(guān)閉了,但更換產(chǎn)品時(shí),客戶(hù)代碼還是需要修改)
Java設(shè)計(jì)模式系列
- Java設(shè)計(jì)模式(一) 簡(jiǎn)單工廠(chǎng)模式不簡(jiǎn)單
- Java設(shè)計(jì)模式(二) 工廠(chǎng)方法模式
- Java設(shè)計(jì)模式(三) 抽象工廠(chǎng)模式
- Java設(shè)計(jì)模式(四) 觀(guān)察者模式
- Java設(shè)計(jì)模式(五) 組合模式
- Java設(shè)計(jì)模式(六) 代理模式 VS. 裝飾模式
- Java設(shè)計(jì)模式(七) Spring AOP JDK動(dòng)態(tài)代理 vs. cglib
- Java設(shè)計(jì)模式(八) 適配器模式
- Java設(shè)計(jì)模式(九) 橋接模式
- Java設(shè)計(jì)模式(十) 你真的用對(duì)單例模式了嗎?
- Java設(shè)計(jì)模式(十一) 享元模式
- Java設(shè)計(jì)模式(十二) 策略模式
- Java設(shè)計(jì)模式(十三) 別人再問(wèn)你設(shè)計(jì)模式,叫他看這篇文章