大话设计模式—工厂模式
一、簡介
工廠模式主要是為創(chuàng)建對象提供了接口。工廠模式按照《Java與模式》中的提法分為三類:
這三種模式從上到下逐步抽象,并且更具一般性。還有一種分類法,就是將簡單工廠模式看為工廠方法模式的一種特例,兩個歸為一類。下面是使用工廠模式的兩種情況:
1.在編碼時不能預見需要創(chuàng)建哪種類的實例。
2.系統(tǒng)不應依賴于產品類實例如何被創(chuàng)建、組合和表達的細節(jié) 。
二、簡單工廠模式(Simple Factory)
顧名思義,這個模式本身很簡單,而且使用在業(yè)務較簡單的情況下。
它由三種角色組成(關系見下面的類圖):
1、工廠類角色:這是本模式的核心,含有一定的商業(yè)邏輯和判斷邏輯。在java中它往往由一個具體類實現(xiàn)。
2、抽象產品角色:它一般是具體產品繼承的父類或者實現(xiàn)的接口。在java中由接口或者抽象類來實現(xiàn)。
3、具體產品角色:工廠類所創(chuàng)建的對象就是此角色的實例。在java中由一個具體類實現(xiàn)。
類圖如下:
使用簡單工廠模式來實現(xiàn)一個實例:
用面向對象語言實現(xiàn)一個計算機控制臺程序:(以java為例)
UML類圖如下:
源代碼如下:
Operation.java
package com.caculate;public class Operation {protected double numberA=0;protected double numberB=0;public double getNumberA() {return numberA;}public void setNumberA(double numberA) {this.numberA = numberA;}public double getNumberB() {return numberB;}public void setNumberB(double numberB) {this.numberB = numberB;}public double getResult(){double result=0;return result;} }OperationAdd.java(加法類)
package com.caculate; /***加法類*/ public class OperationAdd extends Operation{public double getResult() {double result=0;result=numberA + numberB;return result;} }OperationSub.java(減法類)
package com.caculate; /***減法類*/ public class OperationSub extends Operation{public double getResult() {double result=0;result=numberA - numberB;return result;} }OperationMul.java(乘法類)
package com.caculate; /***乘法類*/ public class OperationMul extends Operation{public double getResult() {double result = 0;result=numberA * numberB;return result;} }OperationDiv.java(除法類)
package com.caculate; /***除法類*/ public class OperationDiv extends Operation{public double getReault() {double result=0;result=numberA/numberB;return result;} }OperationFactory.java(工廠類,用來實例化需要用到的運算類對象)
package com.caculate; /***構建一個工廠類來實例化對象*/ public class OperationFactory {/*** @param operate 傳入一個操作符* @return 返回一個對應該操作數(shù)的Operation類對象*/public static Operation createOperate(String operate){Operation oper=null;int n=0;if (operate.equals("+")) {n=1;}if (operate.equals("-")) {n=2;}if (operate.equals("*")) {n=3;}if (operate.equals("、")) {n=4;}/**注意:* JRE1.7以下的版本中,switch的判斷條件必須是一個int型值,也可以是byte、short、char型值;* 在1.7增加新特性能傳string類型*/switch (n) {case 1:oper=new OperationAdd();//如果傳入的操作符是+,則實例化一個加法類對象break;case 2:oper=new OperationSub();//如果傳入的操作符是-,則實例化一個減法類對象break;case 3:oper=new OperationMul();//如果傳入的操作符是*,則實例化一個乘法類對象break;case 4:oper=new OperationDiv();//如果傳入的操作符是/,則實例化一個除法類對象break;}return oper;} }Test.java(測試類)
package com.caculate;public class Test {public static void main(String[] args) {Operation oper=OperationFactory.createOperate("+");oper.numberA=1;oper.numberB=4;double result=oper.getResult();System.out.println(result);} }運行結果: 5.0
總結:
1、當我們需要修改相應的運算時,只需要修改相應的實現(xiàn)類(加減乘除等的實現(xiàn));當需要增加其他的復雜運算(比如:平方根,立方根等)時,只需要實現(xiàn)相應的運算(既增加運算類的子類),然后增加運算類工廠中的switch分支即可;在使用的時候,只需要輸入運算符號,工廠類就能實例化出合適的對象,通過多態(tài),返回父類的方式來實現(xiàn)計算器的結果,而使用者無需了解具體的實現(xiàn)過程,充分契合了面向對象繼承、封裝和多態(tài)的特性。
2、使用了簡單工廠模式后,我們的程序更加符合現(xiàn)實中的情況;而且客戶端免除了直接創(chuàng)建產品對象的責任,而僅僅負責”消費”產品。
我們舉的例子是最簡單的情況,而在實際應用中,很可能產品是一個多層次的樹狀結構。由于簡單工廠模式中只有一個工廠類來對應這些產品,所以實現(xiàn)起來會很麻煩。所以簡單工廠模式適用于業(yè)務較簡單的情況下。而對于復雜的業(yè)務環(huán)境可能不太適應。這就應該由工廠方法模式來出場了。
三、工廠方法模式(Factory Method)
簡單工廠模式最大的優(yōu)點在于工廠類中包含了必要的邏輯判斷,根據(jù)客戶端的選擇條件動態(tài)實例化相關的類,對于客戶端來說,去除了與具體產品的依賴。但是,如果我們要加一個“求M數(shù)的N次方的功能”,我們是一定需要給運算工廠類的方法里加“case”分支條件的,這就修改了原來的類,就等于我們不但對擴展開放了,也對修改開放了,違背了開放-封閉原則。
于是,工廠方法模式就來了。
工廠方法模式(Factory Method)定義一個用于創(chuàng)建對象的接口,讓子類決定實例化哪一個類。工廠方法使一個類的實例化延遲到其子類。
工廠方法模式結構圖如下:
還是以上面的計算器為例子,既然這個工廠類與分支耦合,那么我們就對它下手,根據(jù)依賴倒轉原則,我們把工廠類抽象出一個接口,這個接口只有一個方法,就是創(chuàng)建抽象產品的工廠方法。然后,所有的要生產具體類的工廠,就去實現(xiàn)這個接口。這樣,一個簡單工廠模式的工廠類,變成了一個工廠抽象接口和多個具體生成對象的工廠,于是我們增加“求M數(shù)的N次方”的功能時,就不需要更改原有的工廠類,只需要增加此功能的運算類和相應的工廠類就可以了。
這樣,整個工廠和產品體系都沒有修改的變化而只是擴展的變化,這就完全符合開放-封閉原則的精神,同時又保持了封裝對象創(chuàng)建過程的優(yōu)點,降低了客戶端與產品對象的耦合。
另外,工廠方法模式實現(xiàn)時,客戶端需要決定實例化哪一個工廠來實現(xiàn)運算類,選擇判斷的問題還是存在的,也就是說,工廠方法把簡單工廠方法的內部邏輯判斷移到了客戶端代碼來進行。如果想要增加功能,本來是改工廠類,而現(xiàn)在是修改客戶端。
工廠方法模式是簡單工廠模式的進一步抽象和推廣。由于使用了多態(tài)性,工廠方法模式保持了簡單工廠模式的優(yōu)點,而且克服了它的缺點。但還存在不足,就是由于每增加一個產品,就需要增加一個產品工廠的類,增加了額外的開發(fā)量。這樣,又有一個問題拋出來了,還有沒有可以避免修改客戶端的實現(xiàn)方法呢?
四、抽象工廠模式(Abstract Factory)
以一個簡單的數(shù)據(jù)庫訪問程序來系統(tǒng)學習抽象工廠模式。
首先,我們結合上面剛學到的工廠方法模式來實現(xiàn)這個數(shù)據(jù)庫訪問程序,類圖如下:
客戶端代碼:
public static void main(String[] args) {User user = new User();IFactory factory = new SqlServerFactory();//數(shù)據(jù)庫為sqlserver時//IFactory factory = new AccessFactory();//數(shù)據(jù)庫為access時IUser iu = factory.createUser();iu.insert(user);//插入用戶iu.getUser(1);//得到ID為1的用戶Console.Read();}如果要換數(shù)據(jù)庫,我們只需要把new SqlServerFactory()改為new AccessFactory(),此時由于多態(tài)的關系,使得聲明IUser接口的對象iu事先根本不知道是在訪問哪個數(shù)據(jù)庫,卻可以在運行時很好的完成工作,這就是所謂的業(yè)務邏輯與數(shù)據(jù)庫操作解耦。
如果我們在數(shù)據(jù)庫中增加一個Department(部門表),就涉及到解決這種涉及到多個產品系列的問題,那么,抽象工廠模式就可以粉墨登場了。
(IFactory接口下也有一個CreateDepartment()方法,畫圖時漏掉了)
那么,我們需要在原程序的基礎上做如下改動:
1、增加一個Department類;
2、增加一個IDepartment接口,用于客戶端訪問,解除與具體數(shù)據(jù)庫訪問的耦合;
3、增加一個SqlserverDepartment類,用于訪問SQL Server的Department;
4、增加一個AccessDepartment類,用于訪問Access的Department;
5、IFactory接口是定義一個創(chuàng)建訪問Department表對象的抽象的工廠接口,增加CreateDepartment()方法,相應的SqlServerFactory和AccessFactory類都要增加該方法;
客戶端代碼如下:
public static void main(String[] args) {User user = new User();IFactory factory = new SqlServerFactory();//數(shù)據(jù)庫為sqlserver時//IFactory factory = new AccessFactory();//數(shù)據(jù)庫為access時IUser iu = factory.createUser();iu.insert(user);//插入用戶iu.getUser(1);//得到ID為1的用戶IDepartment id = factory.createDepartment();id.insert(dept);//插入部門id.getDept(1);//得到ID為1的部門Console.Read();}抽象工廠模式(Abstract Method),提供一個創(chuàng)建一系列相關或者相互依賴對象的接口,而無需指定它們具體的類。
抽象工廠模式的優(yōu)點:是易于交換產品系列,由于具體工廠類在一個應用中只需要在初始化的時候出現(xiàn)一次,這就使得改變一個應用的具體工廠變得非常容易,它只需要改變具體工廠即可使用不同的產品配置。我們的設計不能去防止需求的更改,那么我們的理想便是讓改動變的最小,現(xiàn)在如果你要更改數(shù)據(jù)庫訪問,我們只需要更改具體工廠就可以做到。第二大好處是它讓具體的創(chuàng)建實例過程與客戶端分離,客戶端是通過它們的抽象接口操縱實例,產品的具體類名也被具體工廠的實現(xiàn)分離,不會出現(xiàn)在客戶代碼中。
抽象工廠模式缺點:雖然抽象工廠模式可以很方便的切換兩個數(shù)據(jù)庫訪問的代碼,但是如果你的需求來自增加功能,比如我們現(xiàn)在要增加項目表Project,就至少需要增加三個類,IProject、SqlserverProject、AccessProject,還需要更改IFactory、SqlserverFactory和AccessFactory才可以完全實現(xiàn)。而且,我們的客戶端程序類顯然不會只是一個,有很多地方都在使用IUser或者IDepartment,而這樣的設計,我們在更改數(shù)據(jù)庫的時候,所有的地方都要發(fā)生改動,這么大批量的改動顯然是非常糟糕的。
使用簡單工廠模式來改進抽象工廠模式
總結
以上是生活随笔為你收集整理的大话设计模式—工厂模式的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【JFreeChart】JFreeCha
- 下一篇: servlet实现用户登录