簡單工廠模式嚴(yán)格來說并不是一個(gè)設(shè)計(jì)模式,反而較像是一種編程習(xí)慣。
定義
簡單工廠模式(Simple Factory Pattern):又稱為靜態(tài)工廠方法(Static Factory Method)模式,它屬于類創(chuàng)建型模式。在簡單工廠模式中,可以根據(jù)參數(shù)的不同返回不同類的實(shí)例。簡單工廠模式專門定義一個(gè)類來負(fù)責(zé)創(chuàng)建其他類的實(shí)例,被創(chuàng)建的實(shí)例通常都具有共同的父類。
結(jié)構(gòu)

簡單工廠包含了一下角色:
Factory: 工廠角色
負(fù)責(zé)根據(jù)不同的參數(shù)創(chuàng)建不同的實(shí)例。IProduct: 抽象產(chǎn)品角色
所有產(chǎn)品實(shí)例的接口,負(fù)責(zé)描述所有產(chǎn)品實(shí)例的行為。Product(A B ..): 具象產(chǎn)品角色
所有產(chǎn)品的實(shí)例,實(shí)現(xiàn)了抽象產(chǎn)品定義的代碼
場景示例:
簡單工廠應(yīng)用的場景比較對,那么就根據(jù)作者的理解,拿作者工作中遇到的場景需求舉例:
平臺做一個(gè)機(jī)票代購業(yè)務(wù),對接了兩個(gè)供應(yīng)商A、B,用戶選擇完機(jī)票后,平臺拿著機(jī)票去供應(yīng)商下單。下單時(shí)根據(jù)機(jī)票由那個(gè)供應(yīng)商提供去相應(yīng)的供應(yīng)商去下單。
第一步就是定義一個(gè)下單接口。
public interface IVender {
/**
* 供應(yīng)商下單方法
*/
void order();
}
然后分別實(shí)現(xiàn)A、B供應(yīng)商的下單方法。
public class VendorA implements IVender {
@Override
public void order() {
// 業(yè)務(wù)邏輯處理
System.out.println("A供應(yīng)商下單成功,下單時(shí)間" + new Date());
}
}
public class VendorB implements IVender {
@Override
public void order() {
// 業(yè)務(wù)邏輯處理
System.out.println("B供應(yīng)商下單成功,下單時(shí)間:" + new Date());
}
}
接著定義一個(gè)工廠類,根據(jù)傳入的不同參數(shù)請求,分別創(chuàng)建不同的供應(yīng)商實(shí)例并返回,若碰到無效的參數(shù),則拋出異常。
public class VendorFactory {
public static IVender createVendor(String type) {
switch (type) {
case "A":
return new VendorA();
case "B":
return new VendorB();
default:
throw new RuntimeException("供應(yīng)商不存在");
}
}
}
最后,由我們客戶端進(jìn)行調(diào)用:
public class Client {
public static void main(String[] args) {
String type = "A";
IVender iVender = VendorFactory.createVendor(type);
iVender.order();
}
}
如果我們都寫在一個(gè)類中:
public class Client2 {
private static final String TYPE_A = "A";
private static final String TYPE_B = "B";
public static void main(String[] args) {
String type = "A";
if (Objects.equals(TYPE_A, type)) {
// A 供應(yīng)商下單邏輯處理
System.out.println("A供應(yīng)商下單成功,下單時(shí)間" + new Date());
} else if (Objects.equals(TYPE_B, type)) {
// B 供應(yīng)商下單邏輯處理
System.out.println("A供應(yīng)商下單成功,下單時(shí)間" + new Date());
} else {
throw new RuntimeException("供應(yīng)商不存在");
}
}
}
第二種寫法,供應(yīng)商下單邏輯較多的話會(huì)使客戶端變得十分復(fù)雜,后期維護(hù)起來也將是一個(gè)災(zāi)難。如果新增加一個(gè)供應(yīng)商,將會(huì)對這個(gè)類有這較大的改動(dòng),很明顯的違反了開閉原則與迪米特法則。
優(yōu)點(diǎn)
- 工廠類含有必要的判斷邏輯,可以決定在什么時(shí)候創(chuàng)建哪一個(gè)產(chǎn)品類的實(shí)例,客戶端可以免除直接創(chuàng)建產(chǎn)品對象的責(zé)任,而僅僅“消費(fèi)”產(chǎn)品;簡單工廠模式通過這種做法實(shí)現(xiàn)了對責(zé)任的分割,它提供了專門的工廠類用于創(chuàng)建對象。
- 客戶端無須知道所創(chuàng)建的具體產(chǎn)品類的類名,只需要知道具體產(chǎn)品類所對應(yīng)的參數(shù)即可,對于一些復(fù)雜的類名,通過簡單工廠模式可以減少使用者的記憶量。
- 通過引入配置文件,可以在不修改任何客戶端代碼的情況下更換和增加新的具體產(chǎn)品類,在一定程度上提高了系統(tǒng)的靈活性。
缺點(diǎn)
- 由于工廠類集中了所有產(chǎn)品創(chuàng)建邏輯,一旦不能正常工作,整個(gè)系統(tǒng)都要受到影響。
- 使用簡單工廠模式將會(huì)增加系統(tǒng)中類的個(gè)數(shù),在一定程序上增加了系統(tǒng)的復(fù)雜度和理解難度。
- 系統(tǒng)擴(kuò)展困難,一旦添加新產(chǎn)品就不得不修改工廠邏輯,在產(chǎn)品類型較多時(shí),有可能造成工廠邏輯過于復(fù)雜,不利于系統(tǒng)的擴(kuò)展和維護(hù)。
- 簡單工廠模式由于使用了靜態(tài)工廠方法,造成工廠角色無法形成基于繼承的等級結(jié)構(gòu)。
使用場景
在以下情況下可以使用簡單工廠模式:
- 工廠類負(fù)責(zé)創(chuàng)建的對象比較少:由于創(chuàng)建的對象較少,不會(huì)造成工廠方法中的業(yè)務(wù)邏輯太過復(fù)雜。
- 客戶端只知道傳入工廠類的參數(shù),對于如何創(chuàng)建對象不關(guān)心:客戶端既不需要關(guān)心創(chuàng)建細(xì)節(jié),甚至連類名都不需要記住,只需要知道類型所對應(yīng)的參數(shù)。
總結(jié)
- 創(chuàng)建型模式對類的實(shí)例化過程進(jìn)行了抽象,能夠?qū)ο蟮膭?chuàng)建與對象的使用過程分離。
- 簡單工廠模式又稱為靜態(tài)工廠方法模式,它屬于類創(chuàng)建型模式。在簡單工廠模式中,可以根據(jù)參數(shù)的不同返回不同類的實(shí)例。簡單工廠模式專門定義一個(gè)類來負(fù)責(zé)創(chuàng)建其他類的實(shí)例,被創(chuàng)建的實(shí)例通常都具有共同的父類。
- 簡單工廠模式包含三個(gè)角色:工廠角色負(fù)責(zé)實(shí)現(xiàn)創(chuàng)建所有實(shí)例的內(nèi)部邏輯;抽象產(chǎn)品角色是所創(chuàng)建的所有對象的父類,負(fù)責(zé)描述所有實(shí)例所共有的公共接口;具體產(chǎn)品角色是創(chuàng)建目標(biāo),所有創(chuàng)建的對象都充當(dāng)這個(gè)角色的某個(gè)具體類的實(shí)例。
- 簡單工廠模式的要點(diǎn)在于:當(dāng)你需要什么,只需要傳入一個(gè)正確的參數(shù),就可以獲取你所需要的對象,而無須知道其創(chuàng)建細(xì)節(jié)。
- 簡單工廠模式最大的優(yōu)點(diǎn)在于實(shí)現(xiàn)對象的創(chuàng)建和對象的使用分離,將對象的創(chuàng)建交給專門的工廠類負(fù)責(zé),但是其最大的缺點(diǎn)在于工廠類不夠靈活,增加新的具體產(chǎn)品需要修改工廠類的判斷邏輯代碼,而且產(chǎn)品較多時(shí),工廠方法代碼將會(huì)非常復(fù)雜。
- 簡單工廠模式適用情況包括:工廠類負(fù)責(zé)創(chuàng)建的對象比較少;客戶端只知道傳入工廠類的參數(shù),對于如何創(chuàng)建對象不關(guān)心。