一、什么是工廠方法模式
工廠二字想必大家都不陌生,工廠就是用來建造東西的,我們市面上買的東西比如水杯、玩具、汽車等等都是從工廠生產的,那我們需不需要知道它們是如何生產出來的呢?當然不需要,商家從工廠中直接提貨,我們就可以購買了,完全不知道它是如何生產的,這就是工廠方法模式。
工廠方法模式(Factory Method),定義一個用於創建對象的接口,讓子類決定實例化哪一個類。工廠方法模式使一個類的實例化延遲到其子類。UML結構圖如下:

其中,Product定義工廠方法所創建的對象的接口;Creator聲明工廠方法,並返回一個Product類型的對象;ConcreteProduct是具體的產品,實現了Product接口;ConcreteCreteCreator重定義工廠方法,返回一個ConcreteProduct實例。
1. Product類
下述代碼是一個抽象產品類,具體的產品類可以有多個,都繼承於抽象產品類。1 public abstract class Product { 2 //產品類的公共方法 3 public void method1() { 4 //業務邏輯處理 5 } 6 //抽象方法 7 public abstract void method2(); 8 }
2. ConcreteProduct類
具體產品類,可創建多個。
1 public class ConcreteProduct1 extends Product { 2 3 @Override 4 public void method2() { 5 // 業務邏輯處理 6 } 7 8 }
3. Creator類
下述代碼是一個抽象工廠類,主要負責定義產品對象的產生。
1 public abstract class Creator { 2 3 //創建一個產品對象,參數自行設置 4 public abstract <T extends Product> T createProduct(Class<T> c); 5 6 }
4. ConcreteCreator類
具體如何產生一個產品的對象,是由具體的工廠類實現的。
1 public class ConcreteCreator extends Creator { 2 3 @Override 4 public <T extends Product> T createProduct(Class<T> c) { 5 Product product = null; 6 try { 7 product = (Product) Class.forName(c.getName()).newInstance(); 8 } catch (Exception e) { 9 // TODO: handle exception 10 } 11 return (T) product; 12 } 13 14 }
調用時就可以使用我們創建的工廠來完成相應的操作了,如下:
1 Creator creator = new ConcreteCreator(); 2 creator.createProduct(ConcreteProduct1.class);
二、工廠方法模式的應用
1. 何時使用
- 不同條件下創建不用實例時。方法是讓子類實現工廠接口。
2. 優點
- 良好的封裝性,代碼結構清晰。如一個調用者想創建一個對象,只需要知道其名稱即可,降低了模塊間的耦合。
- 擴展性好。如果想增加一個產品,只需擴展一個工廠類即可。
- 屏蔽產品類。調用者只關心產品的接口。
- 典型的解耦框架。
3. 缺點
- 每增加一個產品,就需要增加一個產品工廠的類,增加了系統的復雜度。
4. 使用場景
- 需要生成對象的地方。
- 需要靈活的、可擴展的框架時。
- 數據庫訪問,數據庫可能變化時。
5. 應用實例
- 需要一輛汽車,直接從工廠里面提貨,不用去管這輛車是怎么做出來的。
- Hibernate換數據庫只需換方言和驅動即可。
- 簡單計算器的實現。
三、簡單工廠模式的實現
在看工廠方法模式的實現之前,我們先來了解一下簡單工廠模式。簡單工廠模式就是用一個單獨的類來做創造實例的過程,這個類就是工廠。
我們以簡單計算器的實現為例,這里只給出部分代碼用於與工廠方法模式做對比。UML圖如下:
工廠類如下:
1 public class OperationFactory { 2 public static Operation createOperate(String operate) { 3 Operation oper = null; 4 switch(operate) { 5 case "+": 6 oper = new OperationAdd(); 7 break; 8 case "-": 9 oper = new OperationSub(); 10 break; 11 case "*": 12 oper = new OperationMul(); 13 break; 14 case "/": 15 oper = new OperationDiv(); 16 break; 17 } 18 return oper; 19 } 20 }
其余類參考下方工廠方法模式。
四、工廠方法模式的實現
現在再對這個計算器用工廠方法模式進行編寫,看一下兩種模式間有什么區別。UML圖如下:

1. 運算類
1 public class Operation { 2 3 protected double numberA = 0; 4 protected double numberB = 0; 5 6 public double getNumberA() { 7 return numberA; 8 } 9 public void setNumberA(double numberA) { 10 this.numberA = numberA; 11 } 12 public double getNumberB() { 13 return numberB; 14 } 15 public void setNumberB(double numberB) { 16 this.numberB = numberB; 17 } 18 19 public double getResult() { 20 double result = 0; 21 return result; 22 } 23 }
2. 工廠接口
1 public interface IFactory { 2 Operation createOperation(); 3 }
3. 具體運算類
這里以加減乘除四種運算為例,需要四個實現類,都繼承運算類。
1 public class OperationAdd extends Operation { 2 3 @Override 4 public double getResult() { 5 double result = 0; 6 result = numberA + numberB; 7 8 return result; 9 } 10 11 }
其余三個省略。
4. 運算工廠
有四個運算類,就需要四個運算工廠,都實現了工廠接口。1 public class AddFactory implements IFactory { 2 3 @Override 4 public Operation createOperation() { 5 return new OperationAdd(); 6 } 7 8 }
5. Client客戶端
1 public class Client { 2 3 public static void main(String[] args) { 4 IFactory oFactory = new AddFactory(); 5 // IFactory oFactory = new SubFactory(); 6 // IFactory oFactory = new MulFactory(); 7 // IFactory oFactory = new DivFactory(); 8 9 Operation operation = oFactory.createOperation(); 10 11 operation.numberA = 5; 12 operation.numberB = 7; 13 14 double result = operation.getResult(); 15 System.out.println(result); 16 } 17 18 }
如上述代碼,為加法的運算,若需要進行其他運算,只需實現該接口的其他實現類(如注釋所示)。運行結果如下:

實現加法工廠,進行加法運算,5+7的結果為12。
五、簡單工廠模式與工廠方法模式的區別
如果現在需要增加其他運算,比如取余。簡單工廠模式需要在添加case分支條件,修改了原有的類,違背了開閉原則;而工廠方法模式只需再新加個取余類和取余工廠,然后對客戶端進行修改即可。
簡單工廠模式最大的優點在於工廠類中包含了必要的邏輯判斷,根據客戶端的選擇條件動態實例化相關的類,對與客戶端來說,去除了與具體產品的依賴。為了彌補他違背了開閉原則,於是就有了工廠方法模式,根據依賴倒轉原則,把工廠類抽象出一個接口,這個接口只有一個方法,就是創建抽象產品的工廠方法。
其實工廠方法模式還存在一個問題,就是客戶端需要決定實例化哪一個工廠來實現運算類,也就是說,工廠方法把簡單工廠的內部邏輯判斷移到了客戶端代碼來進行。對於這個問題,可以利用反射來解決(具體實例可參考抽象工廠模式中的反射實例)。

