1 工廠模式介紹
1.1 定義:定義一個用於創建對象的接口,讓子類絕對實例化哪一個類,工廠方法使一個類的實例化延遲到其子類。
工廠方法模式通用類圖:
在工廠模式中,抽象產品類Product負責定義產品的共性,實現對事物最抽象的定義,Creator為抽象類創建類,也就是抽象工廠,具體如何創建產品類是有具體的實現工廠ConcreteCreator完成的。
1.2 工廠方法模式的優點
- 良好的封裝性,代碼結構清晰。
- 擴展性非常優秀,在增加產品類的情況系下,只有適當的修改具體的工廠類或擴展一個工廠類,就可以“擁抱變化”。
- 屏蔽產品類。產品類的實現如何變化,調用者無需關心,它只需關心產品的接口,只要接口保持不變,系統中的上層模塊就不需要發生變化。
- 解耦框架。高層模塊只需要知道產品的抽象類,其他實現類都不用關心。
1.3 工廠方法模式的使用場景
2 工廠模式實現
2.1 簡單工廠模式(靜態工廠模式)
以實現一個計算器為例:
整個過程涉及到三個對象,人(Program4類表示)、計算器(以OperationFactory類表示)、計算方式(計算方式中有多種,加減乘除等,但都屬於計算方法,以一個父類Operation,加減乘除繼承覆寫方法即可)。整個示例類如下圖:
1 public class Program4 { 2 public static void main(String[] args) { 3 try { 4 Scanner scanner = new Scanner (System.in); 5 6 System.out.println ("請輸入數字A:"); 7 double numberA = Double.parseDouble (scanner.nextLine ()); 8 System.out.println ("選擇運算符(+、-、*、/):"); 9 String strOperate = scanner.nextLine (); 10 System.out.println ("請輸入數字B:"); 11 double numberB = Double.parseDouble (scanner.nextLine ()); 12 String strResult = ""; 13 14 if ( strOperate != "/" || numberB != 0){ 15 Operation oper; 16 oper = OperationFactory.createOperate (strOperate); 17 oper.setNumberA (numberA); 18 oper.setNumberB (numberB); 19 20 strResult = String.valueOf (oper.getResult ()); 21 System.out.println ("結果為:"+strResult); 22 23 }else { 24 System.out.println ("除數不能為零"); 25 } 26 27 scanner.close (); 28 } catch (Exception e) { 29 throw new RuntimeException("您輸入有誤:"+e.getMessage ()); 30 } 31 } 32 }
計算器(工廠)根據用戶需求,選擇(生成)符合需要的計算方式創建對應的實例對象,創建過程中需要需用戶參與。
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 }
1 public class Operation{ 2 private double numberA = 0; 3 private double numberB = 0; 4 5 public double getNumberA() { return numberA; } 6 7 public void setNumberA(double numberA) { this.numberA = numberA; } 8 9 public double getNumberB() { return numberB; } 10 11 public void setNumberB(double numberB) { this.numberB = numberB; } 12 13 public double getResult(){ 14 double result = 0; 15 return result; 16 } 17 } 18 19 class OperationAdd extends Operation{ 20 @Override 21 public double getResult() { 22 double result = 0; 23 result = getNumberA () + getNumberB (); 24 return result; 25 } 26 } 27 28 class OperationSub extends Operation{ 29 @Override 30 public double getResult() { 31 double result = 0; 32 result = getNumberA () - getNumberB (); 33 return result; 34 } 35 } 36 37 class OperationMul extends Operation{ 38 @Override 39 public double getResult() { 40 double result = 0; 41 result = getNumberA () * getNumberB (); 42 return result; 43 } 44 } 45 46 class OperationDiv extends Operation{ 47 @Override 48 public double getResult() { 49 double result = 0; 50 result = getNumberA () / getNumberB (); 51 return result; 52 } 53 }
簡單工廠的缺點,不符合“開放封閉原則,要增加新的功能(計算方式)時,需要去修改工廠類(增加分支)。
2.2 多方法模式
是對普通工廠方法模式的改進,在普通工廠方法模式中,如果傳遞的字符串出錯,則不能正確創建對象,而多個工廠方法模式是提供多個工廠方法,分別創建對象。
1 public class OperationFactory03 { 2 3 public Operation add(){ 4 return new OperationAdd(); 5 } 6 7 public Operation sub(){ 8 return new OperationSub (); 9 } 10 11 public Operation mul(){ 12 return new OperationMul(); 13 } 14 15 public Operation div(){ 16 return new OperationDiv(); 17 } 18 }
1 public class FactoryTest { 2 3 public static void main(String[] args) { 4 5 OperationFactory03 factory03 = new OperationFactory03(); 6 Operation add = factory03.add(); 7 8 add.setNumberA(20); 9 add.setNumberB(10); 10 double result = add.getResult(); 11 System.out.println(result); 12 } 13 }
2.3 靜態工廠方法模式
多個工廠方法模式里的方法置為靜態的,不需要創建實例,直接調用即可。
1 public class OperationFactory { 2 3 public static Operation add(){ 4 return new OperationAdd(); 5 } 6 7 public static Operation sub(){ 8 return new OperationSub (); 9 } 10 11 public static Operation mul(){ 12 return new OperationMul(); 13 } 14 15 public static Operation div(){ 16 return new OperationDiv(); 17 } 18 }
1 //調用類 2 public class FactoryTest { 3 4 public static void main(String[] args) { 5 6 Operation add = OperationFactory02.add(); 7 add.setNumberA(20); 8 add.setNumberB(10); 9 double result = add.getResult(); 10 System.out.println(result); 11 12 } 13 }
總體來說,工廠模式適合:凡是出現了大量的產品需要創建,並且具有共同的接口時,可以通過工廠方法模式進行創建。在以上的三種模式中,第一種如果傳 入的字符串有誤,不能正確創建對象,第三種相對於第二種,不需要實例化工廠類,所以,大多數情況下,我們會選用第三種——靜態工廠方法模式。
3 抽象工廠模式
工廠方法模式有一個問題就是,類的創建依賴工廠類,也就是說,如果想要拓展程序,必須對工廠類進行修改,這違背了閉包原則,所以,從設計角度考慮, 有一定的問題,如何解決?就用到抽象工廠模式,創建多個工廠類,這樣一旦需要增加新的功能,直接增加新的工廠類就可以了,不需要修改之前的代碼。因為抽象 工廠不太好理解,我們先看看圖,然后就和代碼,就比較容易理解。
接口類
1 public interface Sender { 2 public void Send(); 3 }
兩個實現類
1 public class MsgSender implements Sender{ 2 3 @Override 4 public void Send() { 5 System.out.println("this is msgsender"); 6 } 7 }
1 public class MailSender implements Sender { 2 3 @Override 4 public void Send() { 5 System.out.println("this is mailsender!"); 6 } 7 }
兩個工廠類
1 public class SendmsgFactory implements Provider { 2 3 @Override 4 public Sender produce() { 5 return new MsgSender(); 6 } 7 }
1 public class SendmailFactory implements Provider { 2 3 @Override 4 public Sender produce() { 5 return new MailSender(); 6 } 7 }
提供一個接口
1 public interface Provider { 2 public Sender produce(); 3 }
測試類
1 public class FactoryTest { 2 public static void main(String[] args) { 3 Provider provider = new SendmailFactory(); 4 Sender sender = provider.produce(); 5 sender.Send(); 6 } 7 }
其實這個模式的好處就是,如果你現在想增加一個功能:發及時信息,則只需做一個實現類,實現Sender接口,同時做一個工廠類,實現Provider接口,就OK了,無需去改動現成的代碼。這樣做,拓展性較好,即依賴抽象不依賴具體原則的體現。