設計模式讀書筆記-----工廠方法模式


        一、問題                                                                                                                   

        在前一章《設計模式讀書筆記-----簡單工廠模式》中通過披薩的實例介紹了簡單工廠模式。在披薩實例中,如果我想根據地域的不同生產出不同口味的披薩,如紐約口味披薩,芝加哥口味披薩。如果利用簡單工廠模式,我們需要兩個不同的工廠,NYPizzaFactory、ChicagoPizzaFactory。在該地域中有很多的披薩店,他們並不想依照總店的制作流程來生成披薩,而是希望采用他們自己的制作流程。這個時候如果還使用簡單工廠模式,因為簡單工廠模式是將披薩的制作流程完全承包了。那么怎么辦?

 

        二、解決方案                                                                                                           

        我們可以這樣解決:將披薩的制作方法交給各個披薩店完成,但是他們只能提供制作完成的披薩,披薩的訂單處理仍然要交給披薩工廠去做。也就是說,我們將createPizza()方法放回到PizzaStore中,其他的部分還是保持不變。

        三、基本定義                                                                                                           

        工廠方法模式定義了一個創建對象的接口,但由子類決定要實例化的類是哪一個。工廠方法模式讓實例化推遲到子類。

 

        四、模式結構                                                                                                            

        工廠方法模式的UML結構圖:

         

        Product:抽象產品。所有的產品必須實現這個共同的接口,這樣一來,使用這些產品的類既可以引用這個接口。而不是具體類。

        ConcreteProduct:具體產品。

        Creator:抽象工廠。它實現了所有操縱產品的方法,但不實現工廠方法。Creator所有的子類都必須要實現factoryMethod()方法。

        ConcreteCreator:具體工廠。制造產品的實際工廠。它負責創建一個或者多個具體產品,只有ConcreteCreator類知道如何創建這些產品。

 

        工廠方法模式是簡單工廠模式的延伸。在工廠方法模式中,核心工廠類不在負責產品的創建,而是將具體的創建工作交給子類去完成。也就是后所這個核心工廠僅僅只是提供創建的接口,具體實現方法交給繼承它的子類去完成。當我們的系統需要增加其他新的對象時,我們只需要添加一個具體的產品和它的創建工廠即可,不需要對原工廠進行任何修改,這樣很好地符合了“開閉原則”。

 

        五、工廠方法模式實現                                                                                            

        針對上面的解決方案,得到如下UML結構圖:

        抽象產品類:Pizza.java

 1 public abstract class Pizza {
 2     protected String name;        //名稱
 3     protected String dough;       //面團
 4     protected String sause;       //醬料
 5     protected List<String> toppings = new ArrayList<String>();       //佐料
 6     
 7     
 8     public void prepare() {
 9         System.out.println("Preparing "+name);
10         System.out.println("Tossing dough");
11         System.out.println("Adding sause");
12         System.out.println("Adding toppings");
13         for(int i = 0;i < toppings.size();i++){
14             System.out.println("   "+toppings.get(i));
15         }
16     }
17 
18     public void bake() {
19         System.out.println("Bake for 25 minutes at 350");
20     }
21 
22     public void cut() {
23         System.out.println("Cutting the pizza into diagonal slices");
24     }
25 
26     public void box() {
27         System.out.println("Place pizza in official PizzaStore box");
28     }
29     
30     public String getName(){
31         return name;
32     }
33 }

 

        具體產品類:NYStyleCheesePizza.java

 1 public class NYStyleCheesePizza extends Pizza{
 2     public NYStyleCheesePizza(){
 3         name = "Ny Style Sauce and Cheese Pizza";
 4         dough = "Thin Crust Dough";
 5         sause = "Marinara Sauce";
 6         
 7         toppings.add("Crated Reggiano Cheese");
 8     }
 9 
10 }

 

        ChicagoStyleCheesePizza.java

 1 public class ChicagoStyleCheesePizza extends Pizza {
 2     public ChicagoStyleCheesePizza(){
 3         name = "Chicago Style Deep Dish Cheese Pizza";
 4         dough = "Extra Thick Crust Dough";
 5         sause = "Plum Tomato Sauce";
 6         
 7         toppings.add("Shredded Mozzarella Cheese");
 8     }
 9     
10     public void cut(){
11         System.out.println("Cutting the Pizza into square slices");
12     }
13 }

 

        抽象工廠:披薩總店。PizzaStore.java

 1 public abstract class PizzaStore {
 2     public Pizza orderPizza(String type){
 3         Pizza pizza;
 4         pizza = createPizza(type);
 5         
 6         pizza.prepare();
 7         pizza.bake();
 8         pizza.cut();
 9         pizza.box();
10         
11         return pizza;
12     }
13     
14     /*
15      * 創建pizza的方法交給子類去實現
16      */
17     abstract Pizza createPizza(String type);
18 }

 

        具體工廠。披薩分店。NYPizzaStore.java

 1 public class NYPizzaStore extends PizzaStore{
 2 
 3     @Override
 4     Pizza createPizza(String item) {
 5         Pizza pizza = null;
 6         if("cheese".equals(item)){
 7             pizza = new NYStyleCheesePizza();
 8         }
 9         else if("veggie".equals(item)){
10             pizza = new NYStyleVeggiePizza();
11         }
12         else if("clam".equals(item)){
13             pizza = new NYStyleClamPizza();
14         }
15         else if("pepperoni".equals(item)){
16             pizza = new NYStylePepperoniPizza();
17         }
18         
19         return pizza;
20     }

 

        ChicagoPizzaStore.java

 1 public class ChicagoPizzaStore extends PizzaStore {
 2     Pizza createPizza(String type) {
 3         Pizza pizza = null;
 4         if("cheese".equals(type)){
 5             pizza = new ChicagoStyleCheesePizza();
 6         }
 7         else if("clam".equals(type)){
 8             pizza = new ChicagoStyleClamPizza();
 9         }
10         else if("pepperoni".equals(type)) {
11             pizza = new ChicagoStylePepperoniPizza();
12         }
13         else if("veggie".equals(type)){
14             pizza = new ChicagoStyleVeggiePizza();
15         }
16         return pizza;
17     }
18 
19 }

 

        做了這么多,應該可以吃披薩了吧。Ethan要一份紐約口味的披薩,Joel需要芝加哥口味的披薩。

        PizzaTestDrive.java

 1 public class PizzaTestDrive {
 2     public static void main(String[] args) {
 3         System.out.println("---------Joel 需要的芝加哥的深盤披薩---------");
 4         ChicagoPizzaStore chicagoPizzaStore = new ChicagoPizzaStore();       //建立芝加哥的披薩店
 5         Pizza joelPizza =chicagoPizzaStore.orderPizza("cheese");             //下訂單
 6         System.out.println("Joel ordered a " + joelPizza.getName() + "\n");
 7         
 8         System.out.println("---------Ethan 需要的紐約風味的披薩---------");
 9         NYPizzaStore nyPizzaStore = new NYPizzaStore();
10         Pizza ethanPizza = nyPizzaStore.orderPizza("cheese");
11         System.out.println("Ethan ordered a " + ethanPizza.getName() + "\n");
12         
13     }
14 }

       運行結果。

 

 

        六、工廠方法模式的優缺點                                                                                      

        優點

           1、  在工廠方法中,用戶只需要知道所要產品的具體工廠,無須關系具體的創建過程,甚至不需要具體產品類的類名。

           2、  在系統增加新的產品時,我們只需要添加一個具體產品類和對應的實現工廠,無需對原工廠進行任何修改,很好地符合了“開閉原則”。

        缺點

           1、  每次增加一個產品時,都需要增加一個具體類和對象實現工廠,是的系統中類的個數成倍增加,在一定程度上增加了系統的復雜度,同時也增加了系統具體類的依賴。這並不是什么好事。

 

        七、工廠方法適用場景                                                                                             

        1、一個類不知道它所需要的對象的類。在工廠方法模式中,我們不需要具體產品的類名,我們只需要知道創建它的具體工廠即可。

        2、一個類通過其子類來指定創建那個對象。在工廠方法模式中,對於抽象工廠類只需要提供一個創建產品的接口,而由其子類來確定具體要創建的對象,在程序運行時,子類對象將覆蓋父類對象,從而使得系統更容易擴展。

        3、將創建對象的任務委托給多個工廠子類中的某一個,客戶端在使用時可以無須關心是哪一個工廠子類創建產品子類,需要時再動態指定。

 

        七、總結                                                                                                                  

         1、工廠方法模式完全符合“開閉原則”。

         2、工廠方法模式使用繼承,將對象的創建委托給子類,通過子類實現工廠方法來創建對象。

         3、工廠方法允許類將實例化延伸到子類進行。

         4、工廠方法讓子類決定要實例化的類時哪一個。在這里我們要明白這並不是工廠來決定生成哪種產品,而是在編寫創建者類時,不需要知道實際創建的產品是哪個,選擇了使用哪個子類,就已經決定了實際創建的產品時哪個了。

         5、在工廠方法模式中,創建者通常會包含依賴於抽象產品的代碼,而這些抽象產品是、由子類創建的,創建者不需要真的知道在制作哪種具體產品。


免責聲明!

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



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