設計模式之工廠方法模式(FACTORY METHOD)

chi633發表於2017-12-21

工廠方法模式定義了一個建立物件的介面,但由子類決定要例項化的類是哪一個。工廠方法讓類把例項化推遲到子類。 我們依然接著簡單工廠模式提出的披薩店問題繼續探討

問題模擬

我們假設有多種不同的pizza店,比如紐約的pizza點,芝加哥的pizza店,他們都有自己製作的不同種類的pizza。 如果我們採用簡單模式方法,那麼我們就需要分別建立紐約pizzafactory和芝加哥的factory等等工廠,但這樣做沒有彈性。我們能不能將製作pizza的行為侷限在旁pizzaStore類中,但同時又能讓不同類的點去各自例項化自己的pizza類。 顯然,我們可以將pizzaStore由一個具體類,變為一個抽象的介面:

public abstract class PizzaStore {
    public Pizza orderPizza(String type) {
      Pizza pizza;
      pizza=createPizza(type);
      pizza.prepare();
      pizza.bake();
      pizza.cut();
      pizza.box();
      return pizza;
  }
  abstract Pizza createPizza(String type);
}
複製程式碼

Paste_Image.png

定義了一個抽象的基類,裡面有個抽象的create方法,我們讓其他的紐約地區,芝加哥地區等等不同的繼承自這個基類,讓子類自己決定怎麼建立pizza。

public class NYPizzaStore extends PizzaStore {
Pizza createPizza(String item) {
if (item.equals(“cheese”)) {
return new NYStyleCheesePizza();
} else if (item.equals(“veggie”)) {
return new NYStyleVeggiePizza();
} else if (item.equals(“clam”)) {
return new NYStyleClamPizza();
} else if (item.equals(“pepperoni”)) {
return new NYStylePepperoniPizza();
} else return null;
}
}
複製程式碼

以上是我們實現的一個具體的紐約pizzastore類。他繼承實現了基類的抽象方法。

然後我們繼承實現抽象的pizza類和具體的pizza類

public abstract class Pizza {
String name;
String dough;
String sauce;
ArrayList toppings = new ArrayList();
void prepare() {
System.out.println(“Preparing “ + name);
System.out.println(“Tossing dough...”);
System.out.println(“Adding sauce...”);
System.out.println(“Adding toppings: “);
for (int i = 0; i < toppings.size(); i++) {
System.out.println(“ “ + toppings.get(i));
}
}
void bake() {
System.out.println(“Bake for 25 minutes at 350”);
}
void cut() {
System.out.println(“Cutting the pizza into diagonal slices”);
}
void box() {
System.out.println(“Place pizza in official PizzaStore box”);
}
public String getName() {
return name;
}
}
複製程式碼

具體的產品類

public class NYStyleCheesePizza extends Pizza {
public NYStyleCheesePizza() {
name = “NY Style Sauce and Cheese Pizza”;
dough = “Thin Crust Dough”;
sauce = “Marinara Sauce”;
toppings.add(“Grated Reggiano Cheese”);
}
}
複製程式碼
public class NYStyleCheesePizza extends Pizza {
public NYStyleCheesePizza() {
name = “NY Style Sauce and Cheese Pizza”;
dough = “Thin Crust Dough”;
sauce = “Marinara Sauce”;
toppings.add(“Grated Reggiano Cheese”);
}
}

public class ChicagoStyleCheesePizza extends Pizza {
public ChicagoStyleCheesePizza() {
name = “Chicago Style Deep Dish Cheese Pizza”;
dough = “Extra Thick Crust Dough”;
sauce = “Plum Tomato Sauce”;
toppings.add(“Shredded Mozzarella Cheese”);
}
void cut() {
System.out.println(“Cutting the pizza into square slices”);
}
}
複製程式碼

最後測試我們的程式碼:

public class PizzaTestDrive {
public static void main(String[] args) {
PizzaStore nyStore = new NYPizzaStore();
PizzaStore chicagoStore = new ChicagoPizzaStore();
Pizza pizza = nyStore.orderPizza(“cheese”);
System.out.println(“Ethan ordered a “ + pizza.getName() + “\n”);
pizza = chicagoStore.orderPizza(“cheese”);
System.out.println(“Joel ordered a “ + pizza.getName() + “\n”);
}
}
複製程式碼

工廠方法模式分析

Paste_Image.png

工廠方法模式常常分為兩大類:一個建立產品的建立類,一個產品類,其中建立類定義一個抽象的介面,外加其餘的繼承自他的具體實現。產品類也是類似,定義一個抽象的產品類介面,具體的產品類實現繼承自基類。

Paste_Image.png

Paste_Image.png

把建立物件的程式碼集中在一個物件或者方法中,可以避免程式碼的重複,並且更方便的以後的維護,這意味著客戶在例項化物件的時候,依賴的是介面,而不是具體的物件,而正是我們之前提到的具體設計原則中的一種,針對介面程式設計。

依賴倒置原則

這是我們提出的又一設計原則:**要依賴抽象,不要依賴具體實現 ** 工廠方法模式中,就很好的應用這個原則: 如果我們採用簡單工廠模式,依賴關係是這樣的:

Paste_Image.png

而採用工廠方法模式,依賴關係如圖:

Paste_Image.png

這就是依賴倒置原則,高層元件依賴了底層的pizza元件!

小結

工廠方法模式對簡單工廠模式進行了抽象。有一個抽象的Factory類(可以是抽象類和介面),這個類將不再負責具體的產品生產,而是隻制定一些規範,具體的生產工作由其子類去完成。在這個模式中,工廠類和產品類往往可以依次對應。即一個抽象工廠對應一個抽象產品,一個具體工廠對應一個具體產品,這個具體的工廠就負責生產對應的產品。

工廠方法經常用在以下兩種情況中:

  • 第一種情況是對於某個產品,呼叫者清楚地知道應該使用哪個具體工廠服務,例項化該具體工廠,生產出具體的產品來。Java Collection中的iterator() 方法即屬於這種情況。
  • 第二種情況,只是需要一種產品,而不想知道也不需要知道究竟是哪個工廠為生產的,即最終選用哪個具體工廠的決定權在生產者一方,它們根據當前系統的情況來例項化一個具體的工廠返回給使用者,而這個決策過程這對於使用者來說是透明的。

相關文章