工廠方法模式定義了一個建立對象的接口,但由子類決定要實例化的類是哪個。工廠方法讓類把實例化推遲到子類。 咱們依然接着簡單工廠模式提出的披薩店問題繼續探討編程
咱們假設有多種不一樣的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);
}
複製代碼
定義了一個抽象的基類,裏面有個抽象的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」);
}
}
複製代碼
工廠方法模式經常分爲兩大類:一個建立產品的建立類,一個產品類,其中建立類定義一個抽象的接口,外加其他的繼承自他的具體實現。產品類也是相似,定義一個抽象的產品類接口,具體的產品類實現繼承自基類。對象
把建立對象的代碼集中在一個對象或者方法中,能夠避免代碼的重複,而且更方便的之後的維護,這意味着客戶在實例化對象的時候,依賴的是接口,而不是具體的對象,而正是咱們以前提到的具體設計原則中的一種,針對接口編程。繼承
這是咱們提出的又一設計原則:**要依賴抽象,不要依賴具體實現 ** 工廠方法模式中,就很好的應用這個原則: 若是咱們採用簡單工廠模式,依賴關係是這樣的:接口
而採用工廠方法模式,依賴關係如圖:
這就是依賴倒置原則,高層組件依賴了底層的pizza組件!
工廠方法模式對簡單工廠模式進行了抽象。有一個抽象的Factory類(能夠是抽象類和接口),這個類將再也不負責具體的產品生產,而是隻制定一些規範,具體的生產工做由其子類去完成。在這個模式中,工廠類和產品類每每能夠依次對應。即一個抽象工廠對應一個抽象產品,一個具體工廠對應一個具體產品,這個具體的工廠就負責生產對應的產品。
工廠方法常常用在如下兩種狀況中: