前言
工廠模式應(yīng)該是大家的老朋友了,相信很多朋友在學(xué)習(xí)和工作中一定遇到過(guò),但是不一定很了解,這篇文章將通過(guò)幾個(gè)例子蛤高,帶大家一起進(jìn)一步了解工廠模式。
簡(jiǎn)介
工廠模式(Factory Pattern)是 Java 中最常用的設(shè)計(jì)模式之一。 這種類(lèi)型的設(shè)計(jì)模式屬于創(chuàng)建型模式 襟齿,它提供了一種創(chuàng)建對(duì)象的最佳方式姻锁。
在創(chuàng)建型模式中工廠模式是比較重要的一種枕赵,之所以名稱(chēng)中包含“工廠”二字猜欺,是因?yàn)橛霉S代替了 new 操作,將對(duì)象實(shí)例化的過(guò)程交給工廠來(lái)實(shí)現(xiàn)拷窜。
工廠模式關(guān)心的是最終創(chuàng)建的對(duì)象, 而不關(guān)心創(chuàng)建的過(guò)程开皿。 舉個(gè)例子,好比您需要一輛汽車(chē)篮昧,可以直接從工廠里面提貨赋荆,而不用去管這輛汽車(chē)是怎么做出來(lái)的,以及這個(gè)汽車(chē)?yán)锩娴木唧w實(shí)現(xiàn)懊昨。
工廠模式可以分為三類(lèi):
簡(jiǎn)單工廠模式 (Simple Factory)
工廠方法模式 (Factory Method)
抽象工廠模式 (Abstract Factory)
其中簡(jiǎn)單工廠模式并不屬于23種 GOF 設(shè)計(jì)模式之一窄潭,而是將其看作工廠方法模式的一種特例,兩者歸為一類(lèi)酵颁。
簡(jiǎn)單工廠模式
簡(jiǎn)單工廠模式又叫靜態(tài)工廠模式嫉你,由一個(gè)工廠類(lèi)根據(jù)傳入的參數(shù),動(dòng)態(tài)決定應(yīng)該創(chuàng)建哪一個(gè)產(chǎn)品類(lèi)(繼承自一個(gè)父類(lèi)或接口)的實(shí)例躏惋。
簡(jiǎn)單工廠模式的主要組成:
工廠(Factory): 負(fù)責(zé)實(shí)現(xiàn)創(chuàng)建所有實(shí)例的內(nèi)部邏輯幽污,并提供一個(gè)外界調(diào)用的方法,創(chuàng)建所需的產(chǎn)品對(duì)象
抽象產(chǎn)品(Product): 負(fù)責(zé)描述產(chǎn)品的公共接口
具體產(chǎn)品(ConcreteProduct): 描述生產(chǎn)的具體產(chǎn)品
這里我們就以生產(chǎn)汽車(chē)為例:
首先定義產(chǎn)品簿姨,先想好要生產(chǎn)什么:
// 汽車(chē)基類(lèi)
public abstract class Car {
// 輸出汽車(chē)信息
public abstract void printInfo();
}
// 比亞迪汽車(chē)
public class BydCar extends Car{
@Override
public void printInfo() {
System.out.println("這是比亞迪汽車(chē)");
}
}
// 吉利汽車(chē)
public class GeelyCar extends Car{
@Override
public void printInfo() {
System.out.println("這是吉利汽車(chē)");
}
}
然后定義工廠類(lèi)距误,想好生產(chǎn)什么產(chǎn)品之后,就要建工廠了:
// 汽車(chē)工廠類(lèi)
public class CarFactory {
// 生產(chǎn)汽車(chē)
public static Car productionCar(String brand) {
if ("geely".equals(brand)) {
return new GeelyCar();
} else if ("byd".equals(brand)) {
return new BydCar();
} else {
return null;
}
}
}
工廠建好了扁位,有了比亞迪和吉利兩條生產(chǎn)線准潭,就可以大膽生產(chǎn)汽車(chē)了:
public class FactoryPatternDemo {
public static void main(String[] args) {
Car car = CarFactory.productionCar("byd");
car.printInfo();
}
}
// 輸出:這是比亞迪汽車(chē)
是不是很簡(jiǎn)單,這時(shí)候可能有朋友就要問(wèn)了域仇,那我想要紅旗汽車(chē)怎么辦刑然,還得再創(chuàng)建一個(gè)紅旗汽車(chē)類(lèi),然后修改工廠類(lèi)的判斷邏輯殉簸,顯然這是違背開(kāi)閉原則的闰集。
那么可不可以不修改工廠類(lèi)里的邏輯呢?
當(dāng)然可以般卑,還有一種方式是通過(guò)反射來(lái)創(chuàng)建具體的產(chǎn)品武鲁,我們熟悉的 Spring 的 BeanFactory 就是采用反射的方式實(shí)現(xiàn)的。
還是汽車(chē)工廠類(lèi)蝠检,我們修改一下代碼:
public class CarFactory {
public static Car productionCar(Class c){
Car car = null;
try {
car = (Car) Class.forName(c.getName()).newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return car;
}
}
反射的方式看起來(lái)代碼簡(jiǎn)潔多了是吧沐鼠,但是某些情況下并不合適,而且反射對(duì)程序性能也會(huì)有影響。
簡(jiǎn)單工廠模式適用于業(yè)務(wù)簡(jiǎn)單的情況下饲梭,而對(duì)于復(fù)雜的業(yè)務(wù)環(huán)境可能就不太適用了乘盖。這個(gè)時(shí)候就要工廠方法模式登場(chǎng)了。
工廠方法模式
在簡(jiǎn)單工廠模式中憔涉,工廠負(fù)責(zé)所有產(chǎn)品的生產(chǎn)订框,就像上面例子中,一個(gè)汽車(chē)工廠負(fù)責(zé)所有汽車(chē)的生產(chǎn)兜叨。而工廠方法模式則是將工廠類(lèi)抽象化穿扳,把生成具體產(chǎn)品的任務(wù)分發(fā)給繼承抽象方法的具體的產(chǎn)品工廠。
工廠方法模式的主要組成:
抽象工廠(Abstract Factory):描述具體工廠的公共接口
具體工廠(ConcreteFactory):描述具體工廠国旷,創(chuàng)建產(chǎn)品的實(shí)例矛物,供外界調(diào)用
抽象產(chǎn)品(Product):負(fù)責(zé)描述產(chǎn)品的公共接口
具體產(chǎn)品(ConcreteProduct):描述生產(chǎn)的具體產(chǎn)品
我們還是以生產(chǎn)汽車(chē)為例:
將簡(jiǎn)單工廠方法中的工廠類(lèi)改為抽象工廠類(lèi),再創(chuàng)建具體工廠類(lèi)來(lái)實(shí)現(xiàn)汽車(chē)的生產(chǎn)工作:
// 抽象汽車(chē)工廠類(lèi)
public abstract class AbstractCarFactory {
// 生產(chǎn)汽車(chē)
abstract Car productionCar();
}
// 比亞迪汽車(chē)工廠
public class BydCarFactory extends AbstractCarFactory{
@Override
Car productionCar()
return new BydCar();
}
}
// 吉利汽車(chē)工廠
public class GeelyCarFactory extends AbstractCarFactory{
@Override
Car productionCar()
return new GeelyCar();
}
}
這下要生產(chǎn)什么品牌的汽車(chē)跪但,就要交給具體的工廠了:
public class FactoryPatternDemo {
public static void main(String[] args) {
AbstractCarFactory factory = new BydCarFactory();
Car car = factory.productionCar();
car.printInfo();
}
}
// 輸出:這是比亞迪汽車(chē)
工廠方法模式看起來(lái)要比簡(jiǎn)單工廠模式更復(fù)雜一些履羞,每增加一個(gè)新的產(chǎn)品就要增加一個(gè)工廠棱烂,但是他提高了系統(tǒng)的可擴(kuò)展性和可維護(hù)性册踩,完全符合開(kāi)閉原則欲侮。
我們可能遇到的大部分業(yè)務(wù)需求使用工廠方法模式足以應(yīng)付墨状,但是凡事都有特殊情況虾攻。當(dāng)產(chǎn)品種類(lèi)更加復(fù)雜芍殖,存在產(chǎn)品族的時(shí)候熄驼,就要使用抽象工廠模式了郭蕉。
抽象工廠模式
在介紹抽象工廠模式前蛤售,我們先了解下產(chǎn)品族是什么:位于不同產(chǎn)品等級(jí)結(jié)構(gòu)中丁鹉,功能相關(guān)聯(lián)的產(chǎn)品組成的家族。
沒(méi)有理解的話可以看下圖:
圖中悴能,比亞迪的商務(wù)汽車(chē)和吉利的商務(wù)汽車(chē)都屬于商務(wù)車(chē)產(chǎn)品族揣钦,運(yùn)動(dòng)車(chē)產(chǎn)品族同理。
抽象工廠模式提供了一種方式漠酿,可以將同一產(chǎn)品族的單獨(dú)的工廠封裝起來(lái)冯凹。它是三種工廠模式里面最為抽象、最具一般性的炒嘲。
抽象工廠模式和工廠方法模式一樣宇姚,都符合開(kāi)閉原則。但是不同的是夫凸,工廠方法模式在增加一個(gè)具體產(chǎn)品的時(shí)候浑劳,都要增加對(duì)應(yīng)的工廠。但是抽象工廠模式只有在新增一個(gè)類(lèi)型的具體產(chǎn)品時(shí)才需要新增工廠夭拌。也就是說(shuō)魔熏,工廠方法模式的一個(gè)工廠只能創(chuàng)建一個(gè)具體產(chǎn)品衷咽。而抽象工廠模式的一個(gè)工廠可以創(chuàng)建屬于一類(lèi)類(lèi)型的多種具體產(chǎn)品。工廠創(chuàng)建產(chǎn)品的個(gè)數(shù)介于簡(jiǎn)單工廠模式和工廠方法模式之間蒜绽。
抽象工廠模式的主要組成:
抽象工廠(AbstractFactory):描述具體工廠的公共接口
具體工廠(ConcreteFactory):描述具體工廠镶骗,創(chuàng)建產(chǎn)品的實(shí)例,供外界調(diào)用
抽象產(chǎn)品(族)(AbstractProduct):描述抽象產(chǎn)品的公共接口
具體產(chǎn)品(ConcreteProduct):描述具體產(chǎn)品的公共接口
同樣以生產(chǎn)汽車(chē)為例:
創(chuàng)建商務(wù)汽車(chē)產(chǎn)品族和運(yùn)動(dòng)汽車(chē)產(chǎn)品族相關(guān)類(lèi):
// 商務(wù)汽車(chē)抽象類(lèi)
public abstract class BusinessCar {
public abstract void printInfo();
}
// 比亞迪商務(wù)汽車(chē)
public class BydBusinessCar extends BusinessCar{
@Override
public void printInfo() {
System.out.println("這是比亞迪商務(wù)汽車(chē)");
}
}
// 吉利商務(wù)汽車(chē)
public class GeelyBusinessCar extends BusinessCar{
@Override
public void printInfo(){
System.out.println("這是吉利商務(wù)汽車(chē)");
}
}
// 運(yùn)動(dòng)汽車(chē)抽象類(lèi)
public abstract class SportCar {
public abstract void printInfo();
}
// 比亞迪運(yùn)動(dòng)汽車(chē)
public class BydSportCar extends SportCar{
@Override
public void printInfo()
{
System.out.println("這是比亞迪運(yùn)動(dòng)汽車(chē)");
}
}
// 吉利運(yùn)動(dòng)汽車(chē)
public class GeelySportCar extends SportCar{
@Override
public void printInfo()
{
System.out.println("這是吉利運(yùn)動(dòng)汽車(chē)");
}
}
創(chuàng)建抽象工廠類(lèi)和具體工廠類(lèi):
// 抽象汽車(chē)工廠類(lèi)
public abstract class AbstractCarFactory {
// 生產(chǎn)商務(wù)汽車(chē)
abstract BusinessCar productionBusinessCar();
// 生產(chǎn)運(yùn)動(dòng)汽車(chē)
abstract SportCar productionSportCar();
}
// 比亞迪汽車(chē)工廠
public class BydCarFactory extends AbstractCarFactory{
@Override
public BusinessCar productionBusiness() {
return new BydBusinessCar();
}
@Override
public SportCar productionSport() {
return new BydSportCar();
}
}
// 吉利汽車(chē)工廠
public class GeelyCarFactory extends AbstractCarFactory{
@Override
public BusinessCar productionBusiness() {
return new GeelyBusinessCar();
}
@Override
public SportCar productionSport() {
return new GeelySportCar();
}
}
開(kāi)始生產(chǎn)汽車(chē):
public class FactoryPatternDemo {
public static void main(String[] args) {
AbstractCarFactory factory = new BydCarFactory();
BusinessCar car = factory.BydBusinessCar();
car.printInfo();
}
}
// 輸出:這是比亞迪商務(wù)汽車(chē)
抽象工廠模式除了具有工廠方法模式的優(yōu)點(diǎn)外躲雅,最主要的優(yōu)點(diǎn)就是可以在類(lèi)的內(nèi)部對(duì)產(chǎn)品族進(jìn)行約束鼎姊。但是產(chǎn)品族的擴(kuò)展將是一件十分費(fèi)力的事情,假如產(chǎn)品族中需要增加一個(gè)新的產(chǎn)品吏夯,則幾乎所有的工廠類(lèi)都需要進(jìn)行修改此蜈,不能很好地支持開(kāi)閉原則即横。所以使用抽象工廠模式時(shí)噪生,對(duì)產(chǎn)品等級(jí)結(jié)構(gòu)的劃分是非常重要的。
總結(jié)
三種工廠模式都各有優(yōu)缺點(diǎn)东囚,合適的才是最好的跺嗽,希望大家能夠理解并靈活運(yùn)用,讓自己的代碼變得更優(yōu)雅页藻!
END
往期推薦
就這?Spring 事務(wù)失效場(chǎng)景及解決方案
SpringBoot+Redis 實(shí)現(xiàn)消息訂閱發(fā)布
什么璃吧?你還不會(huì)在GitHub上搜索資源?還不點(diǎn)進(jìn)來(lái)看看废境?
更多精彩推薦畜挨,請(qǐng)關(guān)注公眾號(hào)【靚仔聊編程】