前言
工廠模式應該是大家的老朋友了,相信很多朋友在學習和工作中一定遇到過,但是不一定很了解,這篇文章將通過幾個例子,帶大家一起進一步了解工廠模式。
簡介
工廠模式(Factory Pattern)是 Java 中最常用的設計模式之一。 這種類型的設計模式屬于創(chuàng)建型模式 ,它提供了一種創(chuàng)建對象的最佳方式。
在創(chuàng)建型模式中工廠模式是比較重要的一種,之所以名稱中包含“工廠”二字,是因為用工廠代替了 new 操作,將對象實例化的過程交給工廠來實現(xiàn)。
工廠模式關(guān)心的是最終創(chuàng)建的對象, 而不關(guān)心創(chuàng)建的過程。 舉個例子,好比您需要一輛汽車,可以直接從工廠里面提貨,而不用去管這輛汽車是怎么做出來的,以及這個汽車里面的具體實現(xiàn)。
工廠模式可以分為三類:
其中簡單工廠模式并不屬于23種 GOF 設計模式之一,而是將其看作工廠方法模式的一種特例,兩者歸為一類。
簡單工廠模式
簡單工廠模式又叫靜態(tài)工廠模式,由一個工廠類根據(jù)傳入的參數(shù),動態(tài)決定應該創(chuàng)建哪一個產(chǎn)品類(繼承自一個父類或接口)的實例。
簡單工廠模式的主要組成:
工廠(Factory): 負責實現(xiàn)創(chuàng)建所有實例的內(nèi)部邏輯,并提供一個外界調(diào)用的方法,創(chuàng)建所需的產(chǎn)品對象
抽象產(chǎn)品(Product): 負責描述產(chǎn)品的公共接口
具體產(chǎn)品(ConcreteProduct): 描述生產(chǎn)的具體產(chǎn)品
這里我們就以生產(chǎn)汽車為例:
首先定義產(chǎn)品,先想好要生產(chǎn)什么:
// 汽車基類public abstract class Car { // 輸出汽車信息 public abstract void printInfo();}// 比亞迪汽車public class BydCar extends Car{ @Override public void printInfo() { System.out.println("這是比亞迪汽車"); }}// 吉利汽車public class GeelyCar extends Car{ @Override public void printInfo() { System.out.println("這是吉利汽車"); }}
然后定義工廠類,想好生產(chǎn)什么產(chǎn)品之后,就要建工廠了:
// 汽車工廠類public class CarFactory { // 生產(chǎn)汽車 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)汽車了:
public class FactoryPatternDemo { public static void main(String[] args) { Car car = CarFactory.productionCar("byd"); car.printInfo(); }}// 輸出:這是比亞迪汽是不是很簡單,這時候可能有朋友就要問了,那我想要紅旗汽車怎么辦,還得再創(chuàng)建一個紅旗汽車類,然后修改工廠類的判斷邏輯,顯然這是違背開閉原則的。
是不是很簡單,這時候可能有朋友就要問了,那我想要紅旗汽車怎么辦,還得再創(chuàng)建一個紅旗汽車類,然后修改工廠類的判斷邏輯,顯然這是違背開閉原則的。
那么可不可以不修改工廠類里的邏輯呢?
當然可以,還有一種方式是通過反射來創(chuàng)建具體的產(chǎn)品,我們熟悉的 Spring 的 BeanFactory 就是采用反射的方式實現(xiàn)的。
還是汽車工廠類,我們修改一下代碼:
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; }}
反射的方式看起來代碼簡潔多了是吧,但是某些情況下并不合適,而且反射對程序性能也會有影響。
簡單工廠模式適用于業(yè)務簡單的情況下,而對于復雜的業(yè)務環(huán)境可能就不太適用了。這個時候就要工廠方法模式登場了。
工廠方法模式
在簡單工廠模式中,工廠負責所有產(chǎn)品的生產(chǎn),就像上面例子中,一個汽車工廠負責所有汽車的生產(chǎn)。而工廠方法模式則是將工廠類抽象化,把生成具體產(chǎn)品的任務分發(fā)給繼承抽象方法的具體的產(chǎn)品工廠。
工廠方法模式的主要組成:
抽象工廠(Abstract Factory):描述具體工廠的公共接口
具體工廠(ConcreteFactory):描述具體工廠,創(chuàng)建產(chǎn)品的實例,供外界調(diào)用
抽象產(chǎn)品(Product):負責描述產(chǎn)品的公共接口
具體產(chǎn)品(ConcreteProduct):描述生產(chǎn)的具體產(chǎn)品
我們還是以生產(chǎn)汽車為例:
將簡單工廠方法中的工廠類改為抽象工廠類,再創(chuàng)建具體工廠類來實現(xiàn)汽車的生產(chǎn)工作:
// 抽象汽車工廠類public abstract class AbstractCarFactory { // 生產(chǎn)汽車 abstract Car productionCar();}// 比亞迪汽車工廠public class BydCarFactory extends AbstractCarFactory{ @Override Car productionCar() return new BydCar(); }}// 吉利汽車工廠public class GeelyCarFactory extends AbstractCarFactory{ @Override Car productionCar() return new GeelyCar(); }}
這下要生產(chǎn)什么品牌的汽車,就要交給具體的工廠了:
public class FactoryPatternDemo { public static void main(String[] args) { AbstractCarFactory factory = new BydCarFactory(); Car car = factory.productionCar(); car.printInfo(); }}// 輸出:這是比亞迪汽車
工廠方法模式看起來要比簡單工廠模式更復雜一些,每增加一個新的產(chǎn)品就要增加一個工廠,但是他提高了系統(tǒng)的可擴展性和可維護性,完全符合開閉原則。
我們可能遇到的大部分業(yè)務需求使用工廠方法模式足以應付,但是凡事都有特殊情況。當產(chǎn)品種類更加復雜,存在產(chǎn)品族的時候,就要使用抽象工廠模式了。
抽象工廠模式
在介紹抽象工廠模式前,我們先了解下產(chǎn)品族是什么:位于不同產(chǎn)品等級結(jié)構(gòu)中,功能相關(guān)聯(lián)的產(chǎn)品組成的家族。
沒有理解的話可以看下圖:
圖中,比亞迪的商務汽車和吉利的商務汽車都屬于商務車產(chǎn)品族,運動車產(chǎn)品族同理。
抽象工廠模式提供了一種方式,可以將同一產(chǎn)品族的單獨的工廠封裝起來。它是三種工廠模式里面最為抽象、最具一般性的。
抽象工廠模式和工廠方法模式一樣,都符合開閉原則。但是不同的是,工廠方法模式在增加一個具體產(chǎn)品的時候,都要增加對應的工廠。但是抽象工廠模式只有在新增一個類型的具體產(chǎn)品時才需要新增工廠。也就是說,工廠方法模式的一個工廠只能創(chuàng)建一個具體產(chǎn)品。而抽象工廠模式的一個工廠可以創(chuàng)建屬于一類類型的多種具體產(chǎn)品。工廠創(chuàng)建產(chǎn)品的個數(shù)介于簡單工廠模式和工廠方法模式之間。
抽象工廠模式的主要組成:
抽象工廠(AbstractFactory):描述具體工廠的公共接口
具體工廠(ConcreteFactory):描述具體工廠,創(chuàng)建產(chǎn)品的實例,供外界調(diào)用
抽象產(chǎn)品(族)(AbstractProduct):描述抽象產(chǎn)品的公共接口
具體產(chǎn)品(ConcreteProduct):描述具體產(chǎn)品的公共接口
同樣以生產(chǎn)汽車為例:
創(chuàng)建商務汽車產(chǎn)品族和運動汽車產(chǎn)品族相關(guān)類:
// 商務汽車抽象類public abstract class BusinessCar { public abstract void printInfo();}// 比亞迪商務汽車public class BydBusinessCar extends BusinessCar{ @Override public void printInfo() { System.out.println("這是比亞迪商務汽車"); }}// 吉利商務汽車public class GeelyBusinessCar extends BusinessCar{ @Override public void printInfo(){ System.out.println("這是吉利商務汽車"); }}// 運動汽車抽象類public abstract class SportCar { public abstract void printInfo();}// 比亞迪運動汽車public class BydSportCar extends SportCar{ @Override public void printInfo() { System.out.println("這是比亞迪運動汽車"); }}// 吉利運動汽車public class GeelySportCar extends SportCar{ @Override public void printInfo(){ System.out.println("這是吉利運動汽車"); }}
創(chuàng)建抽象工廠類和具體工廠類:
// 抽象汽車工廠類public abstract class AbstractCarFactory { // 生產(chǎn)商務汽車 abstract BusinessCar productionBusinessCar(); // 生產(chǎn)運動汽車 abstract SportCar productionSportCar();}// 比亞迪汽車工廠public class BydCarFactory extends AbstractCarFactory{ @Override public BusinessCar productionBusiness() { return new BydBusinessCar(); } @Override public SportCar productionSport() { return new BydSportCar(); }}// 吉利汽車工廠public class GeelyCarFactory extends AbstractCarFactory{ @Override public BusinessCar productionBusiness() { return new GeelyBusinessCar(); } @Override public SportCar productionSport() { return new GeelySportCar(); }}
開始生產(chǎn)汽車:
public class FactoryPatternDemo { public static void main(String[] args) { AbstractCarFactory factory = new BydCarFactory(); BusinessCar car = factory.BydBusinessCar(); car.printInfo(); }}// 輸出:這是比亞迪商務汽車
抽象工廠模式除了具有工廠方法模式的優(yōu)點外,最主要的優(yōu)點就是可以在類的內(nèi)部對產(chǎn)品族進行約束。但是產(chǎn)品族的擴展將是一件十分費力的事情,假如產(chǎn)品族中需要增加一個新的產(chǎn)品,則幾乎所有的工廠類都需要進行修改,不能很好地支持開閉原則。所以使用抽象工廠模式時,對產(chǎn)品等級結(jié)構(gòu)的劃分是非常重要的。
總結(jié)
三種工廠模式都各有優(yōu)缺點,合適的才是最好的,希望大家能夠理解并靈活運用,讓自己的代碼變得更優(yōu)雅!