簡說設計模式——工廠方法模式


一、什么是工廠方法模式

  工廠二字想必大家都不陌生,工廠就是用來建造東西的,我們市面上買的東西比如水杯、玩具、汽車等等都是從工廠生產的,那我們需不需要知道它們是如何生產出來的呢?當然不需要,商家從工廠中直接提貨,我們就可以購買了,完全不知道它是如何生產的,這就是工廠方法模式。

       工廠方法模式(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分支條件,修改了原有的類,違背了開閉原則;而工廠方法模式只需再新加個取余類和取余工廠,然后對客戶端進行修改即可。

       簡單工廠模式最大的優點在於工廠類中包含了必要的邏輯判斷,根據客戶端的選擇條件動態實例化相關的類,對與客戶端來說,去除了與具體產品的依賴。為了彌補他違背了開閉原則,於是就有了工廠方法模式,根據依賴倒轉原則,把工廠類抽象出一個接口,這個接口只有一個方法,就是創建抽象產品的工廠方法。

       其實工廠方法模式還存在一個問題,就是客戶端需要決定實例化哪一個工廠來實現運算類,也就是說,工廠方法把簡單工廠的內部邏輯判斷移到了客戶端代碼來進行。對於這個問題,可以利用反射來解決(具體實例可參考抽象工廠模式中的反射實例)。

 

       源碼地址:https://gitee.com/adamjiangwh/GoF

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM