當看到new時,就會想到具體這個詞。java
是的,當使用new時,確實是在實例化一個具體累,因此用的確實是實現,而不是接口。針對接口編程,能夠隔離掉之後系統可能發生的一大堆改變。由於若是代碼是針對接口編寫的,那麼經過多態,可使用任何接口的實現類。編程
除了使用new操做符以外,還有更多製造對象的方法。實例化這個活動不該該老是公開地進行。設計模式
假設有一個披薩店,須要一個披薩管理系統。ide
咱們決定使用面向對象的方式來實現這個系統,通過分析後,代碼可能會這麼寫:函數
/** * 這裏一個披薩店的實現類。 * */ public class PizzaStore { /** * 訂購披薩的方法,返回一個披薩餅對象。 * */ public Pizza orderPizza() { // 建立一個披薩餅對象。 Pizza pizza = new Pizza("披薩餅"); return pizza; } }
作法是定義一個Pizza類,有一個name字段,重寫toString()方法。測試
接着編寫一個PizzaStore類,該類有一個orderPizza()方法,用於訂購披薩。this
最後編寫main函數進行測試。spa
通過一段時間後,披薩店有了更多種類的披薩餅,簡單的一個Pizza對象已經應付不來了。咱們須要更多的披薩對象,爲了讓系統有彈性,咱們把Pizza類定義爲抽象的,讓具體的披薩對象集成它。設計
/** * 披薩對象的抽象類,全部類型的披薩對象繼承自該類。 * */ public abstract class Pizza { public Pizza() { } public Pizza(String name) { this.name = name; } /** * 對披薩進行前期處理。 * 擀麪、加佐料等工藝。 * */ public void prepare() { System.out.println(" ==> 對" + name + "進行前期處理..."); } /** * 烘培披薩。 * */ public void bake() { System.out.println(" ==> 對" + name + "進行烘培處理..."); } /** * 切割披薩。 * */ public void cut() { System.out.println(" ==> 對" + name + "進行切割處理..."); } /** * 包裝處理。 * */ public void box() { System.out.println(" ==> 對" + name + "進行包裝處理..."); } @Override public String toString() { return "披薩 [名稱=" + name + "]"; } public String getName() { return name; } public void setName(String name) { this.name = name; } private String name; }
/** * 芝士披薩對象,繼承自披薩抽象類。 * */ public class CheesePizza extends Pizza { public CheesePizza() { super.setName("芝士披薩"); } } /** * 希臘披薩,繼承自披薩抽象類。 * */ public class GreekPizza extends Pizza { public GreekPizza() { super.setName("希臘披薩"); } } /** * 意大利香腸披薩,繼承自披薩抽象類。 * */ public class PepperoniPizza extends Pizza { public PepperoniPizza() { super.setName("意大利香腸披薩"); } }
咱們有了具體的披薩類型,接着重寫orderPizza方法,經過類型來決定建立具體的披薩:code
/** * 這裏一個披薩店的實現類。 * */ public class PizzaStore { /** * 訂購披薩的方法,返回一個披薩餅對象。 * */ public Pizza orderPizza(String type) { Pizza pizza; // 經過類型來肯定返回哪一種披薩。 if("cheese".equals(type)) { pizza = new CheesePizza(); } else if ("greek".equals(type)) { pizza = new GreekPizza(); } else if ("pepperoni".equals(type)) { pizza = new PepperoniPizza(); } else { return null; } // 擀麪上料、烘培、切片、裝盒。 pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); return pizza; } }
進行測試:
經過披薩類型訂購了兩種不一樣的披薩,很是方便,可是……
通過了一段時間,有出現了披薩新種類,好比海鮮蛤哩披薩和素食披薩等等,披薩店也學會了這些披薩的作法並要把它們加入到系統中。同時,希臘風味披薩賣得不太好,要將它從系統中移除。
很明顯,若是實例化「某些」具體類,每次都要去修改PizzaStore類源碼,由於要修改orderPizza()方法中的語句。
還有一點,這段建立披薩的代碼放在了PizzaStore中的ordarPizza () 方法,與pizza的處理方法寫到了一塊兒。若是有一天披薩店的菜單對象也須要建立披薩,則須要拷貝orderPizza()方法中建立披薩的那段if-else代碼到菜單對象。修改時就要修改兩處,若是有20個地方用到了建立披薩的這段代碼呢?
是時候將建立披薩的代碼封裝起來了!
咱們須要將if-else的代碼搬到另外一個對象中,這個新對象只管如何建立披薩。若是任何對象想要建立披薩,找它就對了。咱們稱這個新對象爲「工廠」(factory)。建立這個工廠,並修改現有代碼:
首先修改PizzaStore類中的orderPizza()方法,將new披薩的那段if-else代碼從方法中移除:
接下來建立新對象,披薩工廠:
/** * SimplePizzaFactory是披薩的工廠類,它只作一件事,就是建立披薩。 */ public class SimplePizzaFactory { /** * 經過類型來肯定返回哪一種披薩。 * */ public static Pizza createPizza(String type) { Pizza pizza; // 經過類型來肯定返回哪一種披薩。 if ("cheese".equals(type)) { pizza = new CheesePizza(); } else if ("pepperoni".equals(type)) { pizza = new PepperoniPizza(); } else if ("clam".equals(type)) { pizza = new ClamPizza(); } else if ("veggie".equals(type)) { pizza = new VeggiePizza(); } else { return null; } return pizza; } }
最後,在PizzaStore類的orderPizza()方法中,經過工廠來建立披薩:
/** * 這裏一個披薩店的實現類。 * */ public class PizzaStore { /** * 訂購披薩的方法,返回一個披薩餅對象。 * */ public Pizza orderPizza(String type) { // 經過披薩工廠建立披薩。 Pizza pizza = SimplePizzaFactory.createPizza(type); // 擀麪上料、烘培、切片、裝盒。 pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); return pizza; } }
測試結果以下:
簡單工廠其實不是一個設計模式,反而比較像是一種編程習慣。但因爲常常被使用,因此也概括到了工廠方法中。不要由於簡單工廠不是一個「真正的」模式,就忽略了它的用法。讓咱們來看看如今披薩管理系統的類圖:
PizzaStore是工廠的「客戶」。PizzaStore如今經過SimplePizzaFactory取得披薩實例。
SimplePiazzaFactory是工廠方法,用來建立披薩。
Pizza是「產品」的抽象類,每一個具體產品必須拓展抽象的Pizza類,並設計稱一個具體類。這樣一來,就能夠被工廠建立,並返回給客戶。
到這裏簡單工廠的介紹就差很少了,多謝它爲咱們暖身。接下來登場的是兩個重量級的模式,它們都是工廠。