我的博客:後臺建站,適合java程序員java
工廠模式(Factory Pattern)是最多見的一種設計模式之一。它主要是提供一種建立對象的最佳方法!程序員
與經過new來建立對象不一樣,使用工廠模式建立對象不會對客戶端暴露建立邏輯,而且是經過統一個共同的接口指向新建立的對象。同事工廠模式能將建立對象的代碼集中在一個對象或者方法中,能夠避免代碼中的重複,而且更方便維護。面向接口編程,這樣的代碼更具備彈性,能夠應對將來的擴展。編程
案例:假設你有一個Pizza店,天天要作出不一樣口味的Pizza。設計模式
假設咱們有兩種口味Pizzacookie
/* * 抽象的Pizza類,Pizza製做通常包括準備,烘烤,切塊,包裝。 */ public abstract class Pizza{ // Pizza名稱 protected String name; // 麪糰類型 protected String dough; // 醬料 protected String sauce; // 芝士 protected String cheese; // 蛤蜊 protected String clam; // 佐料 protected List toppings = new ArrayList(); // 準備 public void prepare() { System.out.print("準備食材,添加調料:"); for (int i = 0; i < toppings.size(); i++) { System.out.print(toppings.get(i)+" "); } }; // 烘烤 public void bake() { System.out.println("烘烤20分鐘..."); }; // 切塊 public void cut() { System.out.println("切成x塊..."); }; // 包裝 public void box() { System.out.println("包裝..."); } // setter 和 getter方法省略 }
芝加哥風味的芝士Pizza框架
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"); } public void cut() { System.out.println("Cut the pizza into square slices"); } }
紐約風味的蔬菜Pizza學習
public class NyStyleVeggiePizza extends Pizza{ public NyStyleVeggiePizza() { name = "NY style Sauce and Veggie Pizza"; dough = "Thin Crust Dough"; sauce = "Marinara Sauce"; toppings.add("Grated Reggiano Veggie"); } }
紐約風味的芝士Pizzathis
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"); } }
經過new建立對象設計
// 建立一個紐約風味的芝士Pizza NyStyleCheesePizza nyPizza = new NyStyleCheesePizza();
當使用new獲得一個對象時,確實獲得了一個具體類,是針對具體類實現,而不是接口。代碼綁定具體類會致使代碼脆弱,更缺少彈性。
簡單工廠
public class SimplePizzaFactory { public Pizza createPizza(String type) { Pizza pizza = null; if (type.equals("NyStyleCheesePizza")) { return new NyStyleChieesePizza(); } else if(type.endsWith("ChicagoStyleCheesePizza")) { return new ChicagoStyleCheesePizza(); }else { return null; } } }
// 建立簡單工廠對象 SimplePizzaFactory pizzaFactory = new SimplePizzaFactory(); // 建立Pizza對象 NyStyleChieesePizza myPizza = pizzaFactory.createPizza("NYStyleChieesePizza");
簡單工廠將對象的建立過程進行了封裝,用戶不須要知道具體的建立過程,只須要調用工廠類獲取對象便可。
這種簡單工廠的寫法是經過if else來判斷對象建立過程的。簡單工廠只是把new對象的問題轉移到另外一個類中在實際使用過程當中,違背了 開放-關閉原則,固然有些狀況下能夠經過反射調用來彌補這種不足。
工廠方法模式
定義:定義了一個建立對象的接口,但由子類決定要實例化的類是哪個。工廠方法讓類把實例化推遲到子類。
// 抽象的Pizza工廠 public abstract class PizzaFactory { public Pizza getPizza(String type) { Pizza pizza; pizza = createPizza(type); pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); return pizza; } protected abstract Pizza createPizza(String pizza); }
// 紐約Pizza工廠(芝加哥pizza工廠跟這個相似) public class NYPizzaFactory extends PizzaFactory { protected Pizza createPizza(String type) { if (type.equals("NyStyleChieesePizza")) { return new NyStyleCheesePizza(); } else if (type.equals("NyStyleVeggiePizza")) { return new NyStyleVeggiePizza(); }else { return null; } } }
經過工廠方法建立對象
PizzaFactory pizzaFactory = new NYPizzaFactory(); // 建立一個蔬菜披薩 Pizza pizza = pizzaFactory.createPizza("NyStyleVeggiePizza");
當使用工廠方法建立對象時,是在編寫具體工廠類時決定建立的對象時哪個,選擇使用哪一個工廠類,天然就決定了十幾建立的是哪一個對象。儘管只有一個具體工廠,工廠方法仍是很是有用的!由於它將對象從「實現」從「使用」中解耦,若是增長對象或者改變對象,工廠是不會受到影響的!
抽象工廠模式
定義:提供一個接口,用於建立相關或依賴對象的家族,而不須要明確指定具體類。
抽象原料工廠
// 爲了簡化, 這裏的原料用字符串表示,其實每一個原料應該用一個類表示 public interface PizzaIngredientFactory { public String createDough(); public String createSauce(); public String createChieese(); public String[] createVeggies(); public String createPepperoni(); }
芝士pizza原料工廠
public class CheesePizzaIngredientFactory implements PizzaIngredientFactory { public String createDough() { return "薄地殼比薩生麪糰"; } public String createSauce() { return "紐約專用蘸料"; } public String createChieese() { return "Reggiano乾酪"; } public String[] createVeggies() { return new String[]{"洋蔥","生菜","香菇"}; } public String createPepperoni() { return "意大利辣香腸"; } }
建立pizza工廠
public class ChinaPizzaFactory extends PizzaFactory { public Pizza createPizza(String type) { Pizza pizza = null; PizzaIngredientFactory ingredientFactory = new ChinaPizzaIngredientFactory(); if(type.equals("cheese")) { pizza = new CheesePizza(ingredientFactory); pizza.setName("中國芝士pizza"); }else if (type.equals("clam")) { pizza = new ClamPizza(ingredientFactory); pizza.setName("中國蛤蜊pizza"); } return pizza; } }
// 具體的Pizza類 public class ClamPizza extends Pizza { PizzaIngredientFactory ingredientFactory; public ClamPizza(PizzaIngredientFactory pizzaIngredientFactory) { this.ingredientFactory = pizzaIngredientFactory; } public void prepare() { System.out.println("Preparinging" + name); // 根據pizza自己的特色,從工廠中獲取本身須要的原料 dough = ingredientFactory.createDough(); sauce = ingredientFactory.createSauce(); clam = ingredientFactory.creatClam(); } }
建立一箇中國蛤蜊pizza
// 建立一個Pizza工廠 PizzaFactory pizzaFactory = new ChinaPizzaFactory(); Pizza clamPizza = pizzaFactory.createPizza("clam");
抽象工廠模式將'對象' 與 ‘’組成對象或者對象依賴的類‘’解耦。
經過new來建立對象是面向具體類編程,擴展性差!
簡單工廠把所有的事情都在一個地方處理完了,可是當有新增或者修改的對象類時,很難進行擴展,違反了開閉原則。簡單工廠並不能算是工廠模式,而是一種編程習慣,或者是一種方法的封裝,並不具有彈性。
工廠方法是建立一個框架,讓子類決定如何實現。雖然可能致使類會變多,代碼稍微複雜,可是這樣作最大的好處是更具備彈性。
工廠模式的好處:將建立對象的代碼集中在一個對象或者方法中,能夠避免代碼中重複的代碼,而且方便之後的維護。依賴接口,而不是具體的類。
如何選擇?
當須要將對象家族和具體的對象集合結合起來時,可使用抽象工廠。
當須要將客戶代碼從須要實例化的具體類中解耦,或者目前還不中知道未來實例化哪些具體類時,可使用工廠方法。