2010年11月8日 星期一

[OO 設計模式] Factory Patterns : 工廠模式

前言 : 
在設計模式中工廠模式此章的開頭, 便先點出問題所在, 為什麼我麼要使用工廠模式. 首先還記得設計原則 : Coding to interface, not implementation. 當每次我們使用 new 這個關鍵字, 其實就是在使用Concrete 的類別而非介面. 而這會牴觸到設計原則 : Open for extension, close for modification (OCP). 當有新的實體類別產生時, 則在你的代碼判斷改使用哪一個實體類別的區段, 便需要變更, 參考下面代碼 : 

  1. Duck duck;  
  2. if(picnic) {  
  3.     duck = new MallardDuck();  
  4. else if(hunting) {  
  5.     duck = new DecoyDuck();  
  6. }  
當有新的Duck 時, 這個if/else 迴圈便需要改變. 因此考慮到設計原則 : Identify the aspects that vary and separate them from what stays the same. 便有工廠模式的產生與應用. 

工廠模式定義與介紹 : 
在這裡書上以Pizza 工廠作為介紹工廠模式的範例, 如同大部分人的直覺, 在Pizza 工廠使用 if/else 來依據不同需求實例化具體的Pizza 類別, 但隨著Pizza 的種類日益龐大, 這個 if/else 便變的相當繁瑣. 因此考慮到將 Pizza 具體實例化的代碼移出到另一個類別, 並由此類別統以產生客製化的Pizza 物件, 參考如下 : 

 
透過上述的改造, 日後如果有新的Pizza 口味, 對方法 orderPizza 來說並不會受到影響, 它只需要對 SimplePizzaFactory 類別進行呼叫並獲得實現 IPizza 介面的物件, 並做接下來應該做的事而完成了對修改的封閉. 而上述介紹的正是 Simple Factory. 雖然它不是一個Design Pattern, 但是卻是用來介紹工廠模式的精隨很好用的範例. 
接著事情變得更加複雜了, 由於PizzaStore 希望能夠透過經銷商來擴大它的服務範圍, 但是不同經銷商卻對Pizza 的口味有不同的堅持. 可能同樣是Cheese Pizza, 經銷商A要鹹一點, 但是經銷商B 卻想要辣一點. 由於不同經銷商造成同樣同樣Pizza 卻有不同的口味, 因此我們需要重新檢視目前的設計. 
首先將PizzaStore 修改成抽象類別 AbstractPizzaStore, 再將此抽像類別提供各經銷商進行方法:createPizza 的客製化, 以提供不同地區獨特的Cheese Pizza, 參考如下代碼 : 
* AbstractPizzaStore 代碼 : 

  1. package hf.dp.ch04.store;  
  2.   
  3. import hf.dp.ch04.proto.IPizza;  
  4.   
  5. public abstract class AbstractPizzaStore {  
  6.       
  7.     public IPizza orderPizza(String type) {  
  8.         IPizza pizza = null;          
  9.         pizza = createPizza(type);  
  10.         pizza.prepare();  
  11.         pizza.bake();  
  12.         pizza.cut();  
  13.         pizza.box();  
  14.         return pizza;  
  15.     }  
  16.       
  17.     public abstract IPizza createPizza(String type); // 提供經銷商客製化Pizza 口味  
  18.   
  19. }  
* ChiagoStylePizzaStore 代碼 : 

  1. package hf.dp.ch04.store;  
  2.   
  3. import hf.dp.ch04.proto.*;  
  4.   
  5. public class ChiagoStylePizzaStore extends AbstractPizzaStore{  
  6.   
  7.     public IPizza createPizza(String type) {  
  8.         if(type.equals("cheese")) {  
  9.             return new ChiagoStyleCheesePizza();  
  10.         } else if(type.equals("clam")) {  
  11.             return new ChiagoStyleClamPizza();  
  12.         } else {  
  13.             return null;  
  14.         }  
  15.     }  
  16. }  
* NYStylePizzaStore 代碼 : 

  1. package hf.dp.ch04.store;  
  2.   
  3. import hf.dp.ch04.proto.*;  
  4.   
  5. public class NYStylePizzaStore extends AbstractPizzaStore{  
  6.   
  7.     @Override  
  8.     public IPizza createPizza(String type) {  
  9.         if(type.equals("cheese")) {  
  10.             return new NYStyleCheesePizza();  
  11.         } else if(type.equals("clam")) {  
  12.             return new NYStyleClamPizza();  
  13.         } else {  
  14.             return null;  
  15.         }  
  16.     }  
  17. }  
而上面的設計即是所謂的工廠方法設計模式, 其定義如下 : 

The Factory Method Pattern defines an interface for creating an object, but lets subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses.

工廠方法模式 UML 圖 : 底下的Creator 就對應到 AbstractPizzaStore, 而 Product 介面就對應到 IPizza. 詳細代碼請參考附件. 
 


範例代碼 : 
* 呼叫工廠方法模式範例代碼 : 藉由不同的PizzaStore 來 order Pizza, 得到不同口味的Pizza. 
package hf.dp.ch04; 

  1. import hf.dp.ch04.store.*;  
  2. import hf.dp.ch04.proto.*;  
  3.   
  4. public class Main {  
  5.   
  6.     /* 
  7.      * 工廠方法模式呼叫範例代碼 
  8.      */  
  9.     public static void main(String[] args) {  
  10.         AbstractPizzaStore pizzaStore = new NYStylePizzaStore();  
  11.         AbstractPizzaStore pizzaStore2 = new ChiagoStylePizzaStore();  
  12.         IPizza cheesePizza = pizzaStore.orderPizza("cheese");  
  13.         System.out.println("John order "+cheesePizza.getName());  
  14.         cheesePizza = pizzaStore2.orderPizza("cheese");  
  15.         System.out.println("John order "+cheesePizza.getName());  
  16.     }  
  17. }  

執行結果 : 

>>Add spicy sauce and toppings
>>Bake for 40 min at 400.
>>Cutting the pizza into small slices
>>Box with 7 inch size.
John order New York Style Cheese Pizza
>>Add hot sauce and toppings
>>Bake for 25 min at 350.
>>Cutting the pizza into diagonal slices
>>Box with 4 inch size.
John order Chiago Style Cheese Pizza


補充說明 : 
* Caterpillar@Design Pattern: Simple Factory 模式 

Simple Factory模式又稱Static Factory模式。一個Simple Factory生產成品,而對客戶端隱藏產品產生的細節,物件如何生成,生成前是否與其它物件建立依賴關係,客戶端皆不用理會,用以將物件生成方式之變化 與客戶端程式碼隔離...

* Caterpillar@Design Pattern: Factory Method 模式 

Factory Method模式在一個抽象類別中留下某個建立元件的抽象方法沒有實作,其它與元件操作相關聯的方法都先依賴於元件所定義的介面,而不是依賴於元件的實現, 當您的成品中有一個或多個元件無法確定時,您先確定與這些元件的操作介面,然後用元件的抽象操作介面先完成其它的工作,元件的實作(實現)則推遲至實現元 件介面的子類完成,一旦元件加入,即可完成您的成品。
簡單地說,如果您希望如何建立父類別中用到的物件這件事,是由子類別來決定,可以使用Factory Method...

沒有留言:

張貼留言

[Git 常見問題] error: The following untracked working tree files would be overwritten by merge

  Source From  Here 方案1: // x -----删除忽略文件已经对 git 来说不识别的文件 // d -----删除未被添加到 git 的路径中的文件 // f -----强制运行 #   git clean -d -fx 方案2: 今天在服务器上  gi...