識別變化的方面
假設你有一個比薩店,你的代碼可能這麼寫:
Pizza orderPizza() {Pizza pizza = new Pizza();// 為了讓系統有彈性,我們很希望這是一個抽象類別或介面。但如果這樣,這些類或介面就無法直接執行個體化。pizza.prepare();pizza.bake();pizza.cut();pizza.box();return pizza;}
但是你需要更多的比薩類型......
所以,必須增加一些代碼,來“決定”適合的比薩類型,然後再“製造”這個比薩:
Pizza orderPizza(String type) {// 現在把比薩類型傳入orderPizza()。Pizza pizza = new Pizza();// 根據比薩的類型,我們執行個體正確的具體類,然後將其賦值給pizza執行個體變數。注意,這裡的任何比薩都必須實現Pizza介面。if (type.equals("cheese")) {pizza = new CheesePizza();} else if (type.equals("greek")) {pizza = new GreekPizza();} else if (type.equals(pepperoni)) {pizza = new PepperoniPizza();}pizza.prepare();pizza.bake();pizza.cut();pizza.box();return pizza;}
但是壓力來自於增加更多的比薩類型
Pizza orderPizza(String type) {Pizza pizza = new Pizza();// 這是變化的部分。隨著時間,比薩菜單改變,這裡就必須一改再改。 ↓↓↓if (type.equals("cheese")) {pizza = new CheesePizza();} /* else if (type.equals("greek")) {// 刪掉某些比薩pizza = new GreekPizza();} */ else if (type.equals(pepperoni)) {pizza = new PepperoniPizza();}// 新增某些比薩else if (type.equals("clam")) {pizza = new ClamPizza();} else if (type.equals("veggie")) {pizza = new VeggiePizza();}// 這是變化的部分。隨著時間,比薩菜單改變,這裡就必須一改再改。↑↑↑// 這裡是我們不想改變的地方。↓↓↓pizza.prepare();pizza.bake();pizza.cut();pizza.box();// 這裡是我們不想改變的地方。↑↑↑return pizza;}
很明顯地,如果執行個體化“某些”具體類,將使orderPizza()出問題,而且也無法讓orderPizza()對修改關閉;但是,現在我們已經知道哪些會改變,哪些不會改變,該是使用封裝的時候了。
封裝建立對象的代碼
要把建立比薩的代碼移到另一個對象中,由這個新對象專職建立比薩。
Pizza orderPizza(String type) {Pizza pizza = new Pizza();// 把建立對象的代碼從orderPizza()中抽離。然後把這部分的代碼搬到另一個對象中,這個新對象只管如何建立比薩。/*if (type.equals("cheese")) {pizza = new CheesePizza();} else if (type.equals("greek"))pizza = new GreekPizza();} else if (type.equals(pepperoni)) {pizza = new PepperoniPizza();} else if (type.equals("clam")) {pizza = new ClamPizza();} else if (type.equals("veggie")) {pizza = new VeggiePizza();}*/pizza.prepare();pizza.bake();pizza.cut();pizza.box();return pizza;}
我們稱這個新對象為“工廠”。
建立一個簡單比薩工廠
// 只做一件事情,幫它的客戶建立比薩。public class SimplePizzaFactory {// 首先,在這個工廠內定義一個createPizza()方法。所有客戶用這個方法來執行個體化新對象。public Pizza createPizza(String type) {Pizza pizza = null;if (type.equals("cheese")) {pizza = new CheesePizza();} else if (type.equals("pepperoni")) {pizza = new PepperoniPizza();} else if (type.equals("clam")) {pizza = new ClamPizza();} else if (type.equals("veggie")) {pizza = new VeggiePizza();}return pizza;}}
重做PizzaStore類
public class PizzaStore {// 為PizzaStore加上一個對SimplePizzaFactory的引用。SimplePizzaFactory factory; // PizzaStore的構造器,需要一個工廠作為參數。public PizzaStore(SimplePizzaFactory factory) { this.factory = factory;} public Pizza orderPizza(String type) {Pizza pizza;// orderPizza()方法通過簡單傳入訂單類型來使用工廠建立比薩。pizza = factory.createPizza(type); pizza.prepare();pizza.bake();pizza.cut();pizza.box();return pizza;}}
定義簡單工廠
簡單工廠其實不是一個設計模式,反而比較像是一種變成習慣。看看比薩店的類圖。