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

工廠方法模式定義了一個建立對象的接口,但由子類決定要實例化的類是哪個。工廠方法讓類把實例化推遲到子類。 咱們依然接着簡單工廠模式提出的披薩店問題繼續探討編程

問題模擬

咱們假設有多種不一樣的pizza店,好比紐約的pizza點,芝加哥的pizza店,他們都有本身製做的不一樣種類的pizza。 若是咱們採用簡單模式方法,那麼咱們就須要分別創建紐約pizzafactory和芝加哥的factory等等工廠,但這樣作沒有彈性。咱們能不能將製做pizza的行爲侷限在旁pizzaStore類中,但同時又能讓不一樣類的點去各自實例化本身的pizza類。 顯然,咱們能夠將pizzaStore由一個具體類,變爲一個抽象的接口:bash

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類。他繼承實現了基類的抽象方法。ui

而後咱們繼承實現抽象的pizza類和具體的pizza類spa

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」);
}
}
複製代碼

最後測試咱們的代碼:code

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() 方法即屬於這種狀況。
  • 第二種狀況,只是須要一種產品,而不想知道也不須要知道到底是哪一個工廠爲生產的,即最終選用哪一個具體工廠的決定權在生產者一方,它們根據當前系統的狀況來實例化一個具體的工廠返回給使用者,而這個決策過程這對於使用者來講是透明的。
相關文章
相關標籤/搜索