設計模式之工廠模式
工廠模式分三種:簡單工廠模式(也叫靜態工廠模式),工廠方法模式(也叫多形性工廠),抽象工廠模式(也叫工具箱)下面會一一舉例。
一、概念
1、什么是工廠模式
這種類型的設計模式屬於創建型模式,它提供了一種創建對象的最佳方式。工廠模式關心的是最終產出(創建)的對象, 而不關心創建的過程。
2、工廠模式的優點
工廠模式主要是為創建對象提供過渡接口,以便將創建對象的具體過程屏蔽隔離起來,達到提高靈活性的目的。同時會給你系統帶來更大的可擴展性和盡量少的修改量。(下面第三點會舉例說明)
3、什么情況使用工廠模式
這也是具體的說明工廠模式優點。我個人認為在任何需要生成復雜對象的地方,都可以考慮使用工廠模式。
我們以線程池的舉例。
ThreadPoolExecutor類的四個構造方法。
public class ThreadPoolExecutor extends AbstractExecutorService { ..... public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit, BlockingQueue<Runnable> workQueue); public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit, BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory); public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit, BlockingQueue<Runnable> workQueue,RejectedExecutionHandler handler); public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit, BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler); ... }
我們可以看到線程池的構造函數要傳入的參數很多參數才能創建對象,但是其實這里很多參數尤其是后面3個參數基本上用默認值,而不需每次傳入。
那看下線程池的工廠模式(都是使用靜態工廠模式創建對象)。
Executors.newCachedThreadPool(); //創建一個緩沖池,緩沖池容量大小為Integer.MAX_VALUE Executors.newSingleThreadExecutor(); //創建容量為1的緩沖池 Executors.newFixedThreadPool(int); //創建固定容量大小的緩沖池
下面是這三個靜態方法的具體實現:
public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); } public static ExecutorService newSingleThreadExecutor() { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>())); } public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()); }
是不是都已經傳入一些默認值,這讓我們無需再思考在構造函數中應該傳入什么值而苦惱,而直接通過工廠模式獲取一個對象。
二、簡單工廠模式
學習簡單工廠模式的時候我用的是一個與人類有相關的例子。人類在世界分為男人和女人,首先定義一個NvWa(女媧)產品的抽象接口
/** * 產品的抽象接口 女媧 */ public interface NvWa { public void say(); }
然后定義男人和女人,同樣都有說話的方法。
/** * man 男人 */ public class Man implements NvWa { @Override public void say() { System.out.println("男人"); } }
/**女人 */ public class Women implements NvWa { @Override public void say() { System.out.println("女人"); } }
最后寫一個工廠類,用來創造男人和女人。第一種方式是使用邏輯判斷的方式實現的。
/** * 簡單工廠 */ public class SampleFactory { public static NvWa makeNvWa(String type){ if(type.equals("man")){ NvWa man = new Man(); return man; }else if(type.equals("wommen")){ NvWa women = new Women(); return women; }else{ System.out.println("生產不出來"); return null; } } }
第二方式是使用java的放射實現的(推薦)
/** * 簡單工廠放射實現 */ public class SampleFactory1 { public static NvWa makeNvWa(Class c){ NvWa nvwa = null; try { nvwa= (NvWa) Class.forName(c.getName()).newInstance(); } catch (ClassNotFoundException e) { System.out.println("類不存在"); e.printStackTrace(); } return nvwa; } }
反射測試類代碼
package com.roc.factory; /** * 簡單工廠測試*/ public class Client { public static void main(String[] args) { NvWa man = SampleFactory1.makeNvWa(Man.class); man.say(); NvWa women = SampleFactory1.makeNvWa(Women.class); women.say(); } }
總結下:
簡單工廠模式實質:是由一個工廠類根據傳入的參數,動態決定應該創建哪一個產品類(這些產品類繼承自一個父類或接口)的實例。簡單工廠模式的創建目標,所有創建的對象都是充當這個角色的某個具體類的實例。
簡單工廠模式缺點:嚴重違反開閉原則,因為這個時候如果女王要造人妖的話,那肯定要修改工廠的方法,這就違反了開閉原則:修改關閉,對擴展開放。
三、工廠方法模式
在簡單的工廠模式里,我們創建了一個類似工具的類來創建相應的具體類對象。正因為其太過簡單,不符合開閉原則。
工廠方法模式就是把簡單工廠中具體的工廠類,划分成兩層:抽象工廠層+具體的工廠子類層。(就是把具體抽象類多添加一層)
網上盜一張圖(非常完美的圖)

具體例子(把上面的具體實現工廠拆分)
NvWaFactory(造人工廠)
public abstract class NvWaFactory { public abstract NvWacreate(); }
Man工廠(具體工廠子類)
public class ManFactory extends NvWaFactory { @Override public NvWa create() { return new Man(); } }
WoMen工廠(具體工廠子類)
public class WomenFactory extends NvWaFactory { @Override public NvWa create() { return new Women(); } }
測試類
/** * 工廠方法模式: */ NvWaFactory factory1 = new ManFactory(); Man man= factory1.create(); man.say();
工廠方法與簡單工廠的區別:
可以看出,普通工廠模式特點:不僅僅做出來的產品要抽象, 工廠也應該需要抽象。
工廠方法的好處就是更擁抱變化。比如現在在需要造人妖你只要在寫個具體的人妖工廠,而不用像簡單工廠去修改makeNvWa方法,所以工廠方法模式不會違反開閉原則。
四、抽象工廠模式
從上面的工廠方法中的結構圖中,我們可以看到其中的具體工廠A和B是兩個完全獨立的。兩者除了都是抽象工廠的子類,沒有任何其他的交集。
可以理解工廠方法模式都是單產品系的。抽象工廠是多產品系 。
再盜一張圖,這張圖解釋非常到位,下面例子如果沒理解,那么再仔細思考這張圖

我們修改下上面的工廠方法中的總工廠
public abstract class AbstractFactory { /** * 生產人類 */ public abstract NvWa createNvWa(); /** * 生產汽車(這個類就不具體些了,理解就好) */ public abstract Car createCar(); }
具體工廠1
/*具體工廠1:這里生產男人和寶馬車 */ public class Factory1 extends AbstractFactory { @Override public NvWa createNvWa() { return new Man(); } @Override public Car createCar() { return new Bmw(); } }
具體工廠2
/*具體工廠2:這里生產女人和奔馳車 */ public class Factory2 extends AbstractFactory { @Override public NvWa createNvWa() { return new Women(); } @Override public Car createCar() { return new Bc(); } }
功能測試
有了這些東西,那么我們就來好好生產一些產品吧.
public class FactoryTest { public static void main(String[] args) { //工廠1生產男人和寶馬 AbstractFactory factory1 = new Factory1(); Man man = factory1.createNvWa(); Bmw bmw = factory1.createCar(); //工廠2生產女人和奔馳 AbstractFactory factory2 = new Factory2(); Women women = factory2.createNvWa(); Bc bc = factory2.createCar(); } }
個人總結下:
簡單工廠模式它的優點就是簡單,而且違背了開閉原則。不過靜態工廠模式在實際中用到比較多。工廠方法模式修復了開閉原則,但它也有一個缺點每次新增一個具體產品類,也要同時新增一個具體工廠類,會造成類太多。
工廠方法模式比抽象工廠也會用的多,因為抽象工廠結構不像工廠方法那樣清晰。
想太多,做太少,中間的落差就是煩惱。想沒有煩惱,要么別想,要么多做。中校【6】
