23種設計模式之工廠模式
披薩項目為例,使用工廠模式設計
需求:方便披薩品種擴展,便於維護,要能運行時擴展
披薩族(組)設計類圖
假設只有原料不同,其他操作如烘焙、切割、打包相同,就把prepare方法設置為抽象方法
一般設計如下
//披薩族抽象類 public abstract class Pizza { protected String name; public abstract void prepare(); public void bake() { System.out.println(name + " baking;"); } public voidPizza族抽象類cut() { System.out.println(name + " cutting;"); } public void box() { System.out.println(name + " boxing;"); } public void setName(String name) { this.name = name; } }
public class CheesePizza extends Pizza { public void prepare() {CheesePizza extends Pizzasuper.setName("CheesePizza"); System.out.println(name + " preparing;"); } }
public class GreekPizza extends Pizza { public void prepare() { super.setName("GreekPizza"); System.out.println(name + " preparing;"); } }GreekPizza extends Pizza
public class PepperPizza extends Pizza { public void prepare() { super.setName("PepperPizza"); System.out.println(name + " preparing;"); } }PepperPizza extends Pizza
public class OrderPizza { public OrderPizza() { Pizza pizza = null; String orderType; do { orderType = getType(); if (orderType.equals("cheese")) { pizza = new CheesePizza(); } else if (orderType.equals("greek")) { pizza = new GreekPizza(); } else if (orderType.equals("pepper")) { pizza = new PepperPizza(); } else { break; } pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); } while (true); } private String getType() { try { BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in)); System.out.println("input pizza type:"); String pizzaType = bufferedReader.readLine(); return pizzaType; } catch (Exception ex) { ex.printStackTrace(); return ""; } } }OrderPizza 用戶通過輸入pizza類型來點pizza
public class PizzaStore { public static void main(String[] args){ OrderPizza orderPizza; orderPizza=new OrderPizza(); } }pizza商店應用PizzaStore
這種設計有個問題就是,如果有新品種,那就要在披薩族中添加(即實現Pizza抽象類),再在OrderPizza類中添加else if判斷,同樣如果刪除披薩品種也要修改這兩個地方
簡單工廠模式就可以把OrderPizza中創建Pizza部分(if else 變化 部分)抽出來
1、簡單工廠模式:定義了一個創建對象的類,由這個類來封裝實例化對象的行為
public class SimplePizzaFactory { public Pizza createPizza(String orderType){ Pizza pizza=null; if (orderType.equals("cheese")) { pizza = new CheesePizza(); } else if (orderType.equals("greek")) { pizza = new GreekPizza(); } else if (orderType.equals("pepper")) { pizza = new PepperPizza(); } return pizza; } }在OrderPizza中抽取出來的方法封裝成簡單工廠SimplePizzaFactory
public class OrderPizza { SimplePizzaFactory simplePizzaFactory; public OrderPizza(SimplePizzaFactory simplePizzaFactory) { setFactory(simplePizzaFactory); } public void setFactory(SimplePizzaFactory simplePizzaFactory) { this.simplePizzaFactory = simplePizzaFactory; Pizza pizza = null; String orderType; do { orderType = getType(); pizza = simplePizzaFactory.createPizza(orderType); pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); } while (true); } private String getType() { try { BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in)); System.out.println("input pizza type:"); String pizzaType = bufferedReader.readLine(); return pizzaType; } catch (Exception ex) { ex.printStackTrace(); return ""; } } } OrderPizza 改造後,就要使用簡單工廠創建披薩實例OrderPizza 改造後,就要使用簡單工廠創建披薩實例
public class PizzaStore { public static void main(String[] args){ OrderPizza orderPizza; orderPizza=new OrderPizza(new SimplePizzaFactory()); } }PizzaStore 傳入簡單工廠實例對象
這樣的簡單工廠設計,增刪披薩品種時只需在披薩族中增刪披薩種類,和修改披薩工廠中方法,不需要改OrderPizza類
2、工廠方法模式:定義了一個創建對象的抽象方法,由子類決定要實例化的類。工廠方法模式將對象的實例化推遲到子類
假如要在倫敦和紐約開披薩分店,地域特色不同,披薩工廠也就不同了,也就是工廠是可變的了,那麽為了不讓OrderPizza類依賴於工廠,就把制作pizza方法變為抽象方法,OrderPizza類也就是抽象類了,也就是把工廠的實現放到子類去實現,倫敦工廠實現倫敦工廠方法,紐約工廠實現紐約工廠方法
開始有個Pizza族,現在又有個Pizza工廠族,即OrderPizza
工廠方法模式設計方案:將披薩項目裏的披薩對象實例化功能抽象成抽象方法,在不同加盟店具體實現功能
public abstract class OrderPizza { public OrderPizza() { Pizza pizza = null; String orderType; do { orderType = getType(); pizza=createPizza(orderType); pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); } while (true); } public abstract Pizza createPizza(String orderType); private String getType() { try { BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in)); System.out.println("input pizza type:"); String orderType = bufferedReader.readLine(); return orderType; } catch (Exception ex) { ex.printStackTrace(); return ""; } } }abstract class OrderPizza裏面有abstract Pizza createPizza(String orderType)
public class LDCheesePizza extends Pizza { public void prepare() { super.setName("LDCheesePizza"); System.out.println(name+" preparing;"); } }LDCheesePizza extends Pizza
public class LDPepperPizza extends Pizza { public void prepare() { super.setName("LDPepperPizza"); System.out.println(name+"preparing;"); } }LDPepperPizza extends Pizza
public class NYCheesePizza extends Pizza { public void prepare() { super.setName("NYCheesePizza"); System.out.println(name+"preparing;"); } }NYCheesePizza extends Pizza
public class NYPepperPizza extends Pizza { public void prepare() { super.setName("NYPepperPizza"); System.out.println(name+"preparing;"); } }NYPepperPizza extends Pizza
public class LDOrderPizza extends OrderPizza { public Pizza createPizza(String orderType) { Pizza pizza = null; if (orderType.equals("cheese")) { pizza = new LDCheesePizza(); } else if (orderType.equals("pepper")) { pizza = new LDPepperPizza(); } return pizza; } }LDOrderPizza extends OrderPizza
public class NYOrderPizza extends OrderPizza { public Pizza createPizza(String orderType) { Pizza pizza=null; if(orderType.equals("cheese")){ pizza=new NYCheesePizza(); }else if(orderType.equals("pepper")){ pizza=new NYPepperPizza(); } return pizza; } }NYOrderPizza extends OrderPizza
public class PizzaStore { public static void main(String[] args){ OrderPizza orderPizza; // orderPizza=new LDOrderPizza(); orderPizza=new NYOrderPizza(); } }PizzaStore
簡單工廠和工廠方法模式,看上去沒有大的區別,但是在大型項目中,工廠方法模式就比較好,靈活性比較好點
3、抽象工廠模式:定義了一個接口用於創建相關或有依賴關系的對象族,而無需明確指定具體類(簡單工廠演化)
public interface AbsFactory { Pizza createPizza(String orderType); }interface AbsFactory工廠接口
public class LDFactory implements AbsFactory { public Pizza createPizza(String orderType) { Pizza pizza = null; if (orderType.equals("cheese")) { pizza = new LDCheesePizza(); } else if (orderType.equals("pepper")) { pizza = new LDPepperPizza(); } return pizza; } }LDFactory implements AbsFactory
public class NYFactory implements AbsFactory { public Pizza createPizza(String orderType) { Pizza pizza=null; if(orderType.equals("cheese")){ pizza=new NYCheesePizza(); }else if(orderType.equals("pepper")){ pizza=new NYPepperPizza(); } return pizza; } }NYFactory implements AbsFactory
public class OrderPizza { private AbsFactory absFactory; public OrderPizza(AbsFactory absFactory) { setFactory(absFactory); } public void setFactory(AbsFactory factory) { Pizza pizza = null; String orderType; this.absFactory = factory; do { orderType=getType(); pizza=absFactory.createPizza(orderType); if(pizza!=null){ pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); } } while (true); } public String getType() { try { BufferedReader bufferedReader=new BufferedReader(new InputStreamReader(System.in)); System.out.println("input pizza type:"); String orderType=bufferedReader.readLine(); return orderType; }catch (Exception ex){ ex.printStackTrace(); return ""; } } }OrderPizza
public class PizzaStore { public static void main(String[] args){ AbsFactory absFactory; OrderPizza orderPizza; absFactory=new LDFactory(); orderPizza=new OrderPizza(absFactory); } }PizzaStore
4、依賴抽象原則
變量不要持有具體類的引用
不要讓類繼承自具體類,要繼承自抽象類或接口
不要覆蓋基類中已實現的方法
23種設計模式之工廠模式