本文我們說一下創建型設計模式中的工廠模式,可細分為三種:分別是簡單工廠模式,工廠方法模式,抽象工廠模式
下面一一講解:
一.簡單工廠模式
簡單工廠模式屬於類的創建型模式,又叫靜態工廠方法模式。通過專門定義一個工廠類來負責創建其他類的實例,被創建的實例通常都具有共同的父類。
簡單工廠模式包含三種角色:
1.工廠角色(Creator)
這是簡單工廠模式的核心,它用來負責實現創建所有實例的內部邏輯。工廠類可以被外界直接調用,創建所需的產品對象。
2.抽象角色(Product)
這是簡單工廠模式所創建的所有對象的父類,它負責描述所有實例所共有的公共接口。該類可以是接口,也可以是抽象類。
3.具體產品角色(Concrete Product)
簡單工廠模式所創建的具體的實例對象。
以上面的UML為例,表示的是一個用簡單工廠方法模式實現的計算器程序。
其中Operator是一個抽象類,其中包含屬性numberA及numberB,還有一個方法getResult()用於返回計算的結果,它的角色是抽象角色(Product)。
下面的AddOperator,SubOperator,MulOperator,DivOperator是Operator的子類,分別代表加減乘除四種運算,他們的角色是具體產品角色(Concrete Product)。
OperatorFactory是工廠類,其中的createOperator()方法用於創建計算器對象。
下面看代碼:
1 /** 2 * 計算器抽象類 3 * Created by lixiuyu 4 */ 5 public abstract class Operator { 6 7 private double numberA = 0.0; 8 private double numberB = 0.0; 9 10 protected abstract double getResult() throws Exception; 11 12 public double getNumberA() { 13 return numberA; 14 } 15 16 public void setNumberA(double numberA) { 17 this.numberA = numberA; 18 } 19 20 public double getNumberB() { 21 return numberB; 22 } 23 24 public void setNumberB(double numberB) { 25 this.numberB = numberB; 26 } 27 }
1 /** 2 * 加法類 3 * Created by lixiuyu 4 */ 5 public class AddOperator extends Operator { 6 7 protected double getResult() { 8 return getNumberA() + getNumberB(); 9 } 10 }
/** * 減法類 * Created by lixiuyu. */ public class SubOperation extends Operator { @Override protected double getResult() { return getNumberA() - getNumberB(); } }
/** * 乘法類 * Created by lixiuyu. */ public class MulOperation extends Operator { @Override protected double getResult() { return getNumberA() * getNumberB(); } }
1 /** 2 * 除法類 3 * Created by lixiuyu. 4 */ 5 public class DivOperation extends Operator { 6 @Override 7 protected double getResult() throws Exception { 8 if(getNumberB() == 0.0){ 9 throw new Exception("除數不能為0"); 10 }else{ 11 return getNumberA() / getNumberB(); 12 } 13 } 14 }
1 /** 2 * 工廠類 3 * Created by lixiuyu. 4 */ 5 public class OperatorFactory { 6 public static Operator createOperator(String operation){ 7 Operator operator = null; 8 switch (operation){ 9 case "+": 10 operator = new AddOperator(); 11 break; 12 case "-": 13 operator = new SubOperator(); 14 break; 15 case "*": 16 operator = new MulOperator(); 17 break; 18 case "/": 19 operator = new DivOperator(); 20 break; 21 } 22 return operator; 23 } 24 }
測試類:
1 /** 2 * Created by lixiuyu. 3 */ 4 public class OperatorTest { 5 public static void main(String[] args) { 6 Operator operator = OperatorFactory.createOperator("+"); 7 operator.setNumberA(10); 8 operator.setNumberB(5); 9 try { 10 System.out.println(operator.getResult()); 11 } catch (Exception e) { 12 e.printStackTrace(); 13 } 14 } 15 }
最后輸出15
這樣寫的計算器是不是比if()...else()...寫出來的好呢?
下面我們分析一下簡單工廠模式的優缺點:
在簡單工廠模式中,工廠類是整個模式的關鍵所在。它包含了必要的判斷邏輯,能夠根據外界給定的條件去判斷應該創建哪個具體類的實例。用戶在使用時可以直接根據工廠類去創建所需的實例,而無需關系這些對象是如何組織並創建的,從這一點上來說,這有利於整個軟件體系結構的優化。
但是,簡單工廠模式的缺點也正體現在工廠類上,由於工廠類中集中了所有實例的創建邏輯,當我們增加了一個新的具體類時,需要同時修改工廠類(多加一個if),這違反了“開閉原則”。
二.工廠方法模式
工廠方法模式是對普通工廠方法模式的改進,在普通工廠方法模式中,如果傳遞的字符串出錯,則不能正確創建對象,而工廠方法模式是提供多個工廠方法,分別創建對象。
依舊以上面的計算器為例,進行講解:
我們對OperatorFactory類更改如下:
1 /** 2 * Created by lixiuyu. 3 */ 4 public class OperatorFactory { 5 6 public static Operator createAddOperator(){ 7 return new AddOperator(); 8 } 9 10 public static Operator createSubOperator(){ 11 return new SubOperator(); 12 } 13 14 public static Operator createMulOperator(){ 15 return new MulOperator(); 16 } 17 18 public static Operator createDivOperator(){ 19 return new DivOperator(); 20 } 21 }
此時將不會出現簡單工廠模式因為字符串傳錯而不能正常創建對象的問題。
1 /** 2 * Created by lixiuyu. 3 */ 4 public class OperatorTest { 5 public static void main(String[] args) { 6 Operator operator = OperatorFactory.createAddOperator(); 7 operator.setNumberA(10); 8 operator.setNumberB(5); 9 try { 10 System.out.println(operator.getResult()); 11 } catch (Exception e) { 12 e.printStackTrace(); 13 } 14 } 15 }
執行結果:15.0
總結:
與簡單工廠模式相比,工廠方法模式避免了因為傳入字符串錯誤導致無法正常創建對象的問題,但需要添加新的具體類時,仍然需要修改工廠類,這仍然違背“開閉原則”。
三.抽象工廠模式
工廠方法模式有一個問題就是,類的創建依賴工廠類,也就是說,如果想要拓展程序,必須對工廠類進行修改,這違背了開閉原則,所以,從設計角度考慮,有一定的問題,如何解決?就用到抽象工廠模式。抽象工廠模式就是將對象工廠的創建抽象到一個接口中。抽象工廠類不在負責產品的創建,僅僅負責定義具體工廠子類必須實現的接口,這樣進一步抽象化的好處是使得可以再不修改具體工廠角色的情況下引進新的產品。
這樣一旦需要增加新的功能,直接增加新的工廠類就可以了,不需要修改之前的代碼,符合開閉原則。
抽象工廠模式中包含的角色及職責:
1.抽象工廠角色(Creator)
這是抽象工廠模式的核心,任何工廠類必須實現這個接口。
2.具體工廠角色(Concrete Creator)
它是抽象工廠的一個實現,負責實例化產品對象。
3.抽象角色(Product)
抽象工廠模式所創建的所有對象的父類,它負責描述所有實例所共有的公共接口。
3.具體產品角色(Concrete Product)
抽象工廠模式所創建的具體的實例對象。
下面結合UML圖理解一下:
在抽象工廠中定義了各個實現類需要實現的接口createOperator(),各個實現類按照各自的規則實例化Operator對象。代碼如下:
1 /** 2 * Created by lixiuyu. 3 */ 4 public interface OperatorFactory { 5 public Operator createOperator(); 6 }
接下來定義OperatorFactory的具體實現類,即具體工廠類。
1 /** 2 * Created by lixiuyu. 3 */ 4 public class AddOperatorFactory implements OperatorFactory { 5 6 @Override 7 public Operator createOperator() { 8 return new AddOperator(); 9 } 10 }
1 /** 2 * Created by lixiuyu. 3 */ 4 public class SubOperatorFactory implements OperatorFactory { 5 @Override 6 public Operator createOperator() { 7 return new SubOperator(); 8 } 9 }
1 /** 2 * Created by lixiuyu. 3 */ 4 public class MulOperatorFactory implements OperatorFactory { 5 @Override 6 public Operator createOperator() { 7 return new MulOperator(); 8 } 9 }
1 /** 2 * Created by lixiuyu. 3 */ 4 public class DivOperatorFactory implements OperatorFactory { 5 @Override 6 public Operator createOperator() { 7 return new DivOperator(); 8 } 9 }
下面是測試類:
1 /** 2 * Created by lixiuyu. 3 */ 4 public class OperatorFactoryTest { 5 6 public static void main(String[] args) { 7 OperatorFactory factory = new AddOperatorFactory(); 8 Operator operator = factory.createOperator(); 9 operator.setNumberA(10.0); 10 operator.setNumberB(5.0); 11 try { 12 System.out.println(operator.getResult()); 13 } catch (Exception e) { 14 e.printStackTrace(); 15 } 16 } 17 }
運行結果:15.0
由此可見,當我們需要增加一種運算時,只需要增加一個具體運算及具體工廠類,原有的具體工廠類不需要做任何改動,即做到了"對擴展開放,對修改關閉",很好的符合了開閉原則。