一.前言
1.準備好開始烘烤某些鬆耦合的OO設計。
2.製造對象的方法除了new,還有很多其他的方法;
3.初始化使用new經常會帶來一些耦合的問題,工廠模式可以解決這個問題;
那麼“new”有什麼不對勁呢?
其實,new沒有問題,有問題的是“改變”。則可以用設計原則“找出會變化的部分,把他們從不變的部分分離出來”。
(即:將實例化具體類的方法抽離,或者封裝起來,使他們不會干擾其他部分。)
4.重要原則--“針對接口編程”。
5.所有工廠模式都是用來封裝對象的創建。
二.披薩店實例--簡單工廠
1.pizza店有許多pizza類型,每種pizza從order開始的流程都要經過準備prepare、烘烤bake、切片cut和裝箱box,所以通常對於OO設計者們,初步可以考慮到這樣的設計:
public class MainTest { public static void main(String[] args) { IPizza pizza = orderPizza(null); if(pizza != null){ pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); } } private static IPizza orderPizza(String type){ if(type == null){ System.out.println("What kind of pizza do you want?"); return null; } IPizza pizza = null; if(type.equals("cheese")){ pizza = new PizzaCheese(); }else if(type.equals("fruit")){ pizza = new PizzaFruit(); }else if(type.equals("banana")){ pizza = new PizzaBanana(); } return pizza; } }
public interface IPizza { /**準備*/ public void prepare(); /**烘烤*/ public void bake(); /**切片*/ public void cut(); /**裝盒*/ public void box(); }
public class PizzaCheese implements IPizza{ public void prepare() { System.out.println("PizzaCheese prepare"); } public void bake() { System.out.println("PizzaCheese bake"); } public void cut() { System.out.println("PizzaCheese cut"); } public void box() { System.out.println("PizzaCheese box"); } }
2.上述中存在一個問題:增加新類型pizza或去除一種賣的不好的pizza,上述創建pizza對象的部分就要一改再改,這裏就是變化的部分,我們要做的,就是分離變化的部分----該使用封裝了。
封裝創建對象的代碼。
(1)將創建對象的代碼移到另一個對象中,這個對象的專職就是創建pizza對象;
(2)稱這個專職對象爲“工廠”SimplePizzaFactory;
(3)此時,orderPizza()就不再需要知道什麼類型的pizza,只管得到一個pizza。
//測試類 public class MainTest { public static void main(String[] args) { //利用工廠創建pizza IPizza pizza = new PizzaShop().orderPizza("banana"); if(pizza != null){ pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); } } } //客戶預訂披薩 class PizzaShop{ public IPizza orderPizza(String type){ //利用工廠創建pizza IPizza pizza = SimplePizzaFactory.createPizza(type); return pizza; } }
public class SimplePizzaFactory { /** * 把原來的創建代碼直接移動過來 * @param type * @return */ public static IPizza createPizza(String type){ if(type == null){ System.out.println("What kind of pizza do you want?"); return null; } IPizza pizza = null; if(type.equals("cheese")){ pizza = new PizzaCheese(); }else if(type.equals("fruit")){ pizza = new PizzaFruit(); }else if(type.equals("banana")){ pizza = new PizzaBanana(); } return pizza; } }
其他部分不變,此後:
當有很多很多“客戶”時,他們都利用該“工廠”創建指定類型的pizza,如果pizza本身種類等發生任何改變,每個“客戶”都不用修改代碼,只需“工 廠”修改即可。
3.以上就是“簡單工廠”:
簡單工廠其實並不是一個設計模式,而是一種編程習慣;
簡單工廠常用爲static,但有時也有缺點,不能利用繼承待改變創建方法的行爲。
三.披薩店實例--工廠方法
1.現有不同區域的披薩店想要做不同口味的披薩。就不能用簡單工廠了。可以考慮將創建對象的功能移到pizzashop的一個抽象方法中,由pizzashop的子類做決定創建具體的對象。
public abstract class PizzaShop { // final的修飾不是必要的,不過這樣可以防止子類覆蓋 public final IPizza orderPizza(String type){ // createPizza()移回PizzaShop中 IPizza pizza = createPizza(type); if(pizza != null){ pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); } return pizza; } // 抽象的“工廠方法” protected abstract IPizza createPizza(String type); }
// 每個子類都要繼承PizzaShop public class BeijingPizzaShop extends PizzaShop{ // 實現抽象的“工廠方法” protected IPizza createPizza(String type) { if(type == null){ System.out.println("BeijingPizzaShop:What kind of pizza do you want?"); return null; } IPizza pizza = null; if(type.equals("cheese")){ pizza = new BeijingPizzaCheese(); }else if(type.equals("fruit")){ pizza = new BeijingPizzaFruit(); }else if(type.equals("banana")){ pizza = new BeijingPizzaBanana(); } return pizza; } }
public class ShenZhenPizzaShop extends PizzaShop{ protected IPizza createPizza(String type) { if(type == null){ System.out.println("ShenZhenPizzaShop kind of pizza do you want?"); return null; } IPizza pizza = null; if(type.equals("cheese")){ pizza = new ShenZhenPizzaCheese(); }else if(type.equals("fruit")){ pizza = new ShenZhenPizzaFruit(); }else if(type.equals("banana")){ pizza = new ShenZhenPizzaBanana(); } return pizza; } }
2.進一步說明:
(1)做到了解耦--orderPizza()是在PizzaShop中定義的,但是他在使用createPizza()創建的pizza對象類執行prepare、bake、cut、box方法時並不知道具體的pizza對象是哪種類型。
(2)pizza對象的具體類型僅由具體的pizza店(顧客)決定。
3.有關工廠方法
(1)簡單工廠是有一個專職對象負責所有具體類的實例化,而工廠方法則是由一羣子類來負責實例化;
(2)將一個orderpizza方法和一個工廠方法聯合起來,可以成爲一個框架;
(3)工廠方法將生產知識封裝進各個創建者,這種做法也可視爲一個框架;
4.定義工廠方法模式
(1)工廠方法模式定義了一個創建對象的接口,但由子類決定要實例化的類是哪一個。工廠方法讓類把實例化推遲到子類。