摘要:工廠模式是將例項化物件的程式碼提取出來,放到一個類中統一管理和維護,達到和主專案的依賴關係的解耦。從而提高專案的擴充套件和維護性。
本文分享自華為雲社群《【Java設計模式】用 披薩訂購案例 詳細講解三種工廠模式》,作者: 我是一棵捲心菜。
一、使用傳統方法
類圖
步驟概括
步驟一:建立一個Pizza抽象類
public abstract class Pizza { public String name; public abstract void prepare(); public void bake() { System.out.println(name + " baking"); } public void cut() { System.out.println(name + " cutting"); } public void box() { System.out.println(name + " boxing"); } public void setName(String name) { this.name = name; } }
分析: 這個類用來代表製作披薩的整個流程:準備階段prepare()
、烘烤階段bake()
、切割階段cut()
和打包階段box()
,假設各個披薩的準備階段需要的材料不一樣,所以把準備階段定義為一個抽象方法 ,其它三個階段都一樣。
步驟二:建立兩個披薩類
public class CheesePizza extends Pizza{ @Override public void prepare() { System.out.println("乳酪披薩正在準備中"); } }
分析: 這個類代表乳酪披薩,簡單重寫一下準備階段
public class BeefPizza extends Pizza{ @Override public void prepare() { System.out.println("牛肉披薩正在準備中"); } }
分析: 這個類代表牛肉披薩,也簡單重寫一下準備階段
步驟三:制定訂購披薩類
public class OrderPizza { public OrderPizza() { Pizza pizza = null; do { String pizzaType = getType(); if ("cheese".equalsIgnoreCase(pizzaType)) { pizza = new CheesePizza(); pizza.setName("cheese"); } else if ("beef".equalsIgnoreCase(pizzaType)) { pizza = new BeefPizza(); pizza.setName("beef"); } else { break; } pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); } while (true); } // 寫一個方法,可以獲取希望訂購的披薩種類 private String getType() { try { BufferedReader strin = new BufferedReader(new InputStreamReader(System.in)); System.out.println("input pizza 種類:"); String str = strin.readLine(); return str; } catch (IOException e) { e.printStackTrace(); return ""; } } }
分析: 慢慢看程式碼,可以明白,訂購披薩的邏輯程式碼寫在了該類的構造器中,getType()方法
是用來獲取希望訂購的披薩種類。但是,如果我們需要新增新的披薩,就需要從這個類中繼續新增相應的邏輯語句,從而修改了訂購披薩的這個類,就違反了OCP原則
步驟四:建立執行類
public class PizzaStore { public static void main(String[] args) { new OrderPizza(); } }
執行結果:
優缺點分析
優點:比較好理解,簡單易操作
缺點:違反了設計模式的ocp原則,即對擴充套件開放,對修改關閉。即當我們給類增加新功能的時候,儘量不修改程式碼,或者儘可能少修改程式碼
二、使用簡單工廠
類圖
基本介紹
簡單工廠模式是屬於建立型模式,是工廠模式的一種。簡單工廠模式是由一個工廠物件決定建立出哪一種產品類的例項。簡單工廠模式是工廠模式家族中最簡單實用的模式
簡單工廠模式定義了一個建立物件的類,由這個類來封裝例項化物件的行為(程式碼)
在軟體開發中,當我們會用到大量的建立某種、某類或者某批物件時,就會使用到工廠模式
步驟概括
步驟一:建立簡單工廠
public class SimpleFactory { public static Pizza createPizza2(String orderType) { Pizza pizza = null; if ("beef".equalsIgnoreCase(orderType)) { pizza = new BeefPizza(); pizza.setName(" beef "); } else if ("cheese".equalsIgnoreCase(orderType)) { pizza = new CheesePizza(); pizza.setName("cheese"); } return pizza; } }
分析: 簡單工廠又叫做靜態工廠,我們寫一個靜態方法,可以方便後面程式碼的呼叫,這裡用到的類,跟用傳統方法用到的類一樣,沒有改變
步驟二:制定訂購披薩類
public class OrderPizza2 { public OrderPizza2() { do { String orderType = getType(); Pizza pizza = SimpleFactory.createPizza2(orderType); if (pizza != null) { pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); } else { System.out.println(" 訂購披薩失敗 "); break; } } while (true); } private String getType() { try { BufferedReader strin = new BufferedReader(new InputStreamReader(System.in)); System.out.println("input pizza 種類:"); String str = strin.readLine(); return str; } catch (IOException e) { e.printStackTrace(); return ""; } } }
分析: 該類的構造器中用到了簡單工廠類SimpleFactory
,這樣,我們就不需要在訂購披薩這一行為中去寫增加新的披薩的程式碼了,而是從工廠中寫新增新的披薩的程式碼,就不用再改動這個類。
執行結果:
優點分析
使用簡單工廠模式來建立物件,更加的方便靈活,不需要修改訂購披薩的邏輯
三、使用工廠方法
新的需求
客戶在點披薩時,可以點不同口味的披薩,比如 北京的乳酪pizza、北京的胡椒pizza 或者是倫敦的乳酪pizza、倫敦的胡椒pizza
類圖
基本介紹
工廠方法模式設計方案:將披薩專案的例項化功能抽象成抽象方法,在不同的口味點餐子類中具體實現。
工廠方法模式:定義了一個建立物件的抽象方法,由子類決定要例項化的類。工廠方法模式將物件的例項化推遲到子類。
步驟概括
步驟一:建立四個披薩類
public class BJCheesePizza extends Pizza { @Override public void prepare() { setName("北京的乳酪pizza"); System.out.println("北京的乳酪pizza 準備原材料"); } }
分析: Pizza
類跟上面的程式碼一樣,我就沒有再次寫了。此類是用來建立北京的乳酪口味的披薩
public class BJPepperPizza extends Pizza{ @Override public void prepare() { setName("北京的胡椒pizza"); System.out.println("北京的胡椒pizza 準備原材料"); } }
分析: 此類是用來建立北京的辣椒口味的披薩
public class LDCheesePizza extends Pizza { @Override public void prepare() { setName("倫敦的乳酪pizza"); System.out.println("倫敦的乳酪pizza 準備原材料"); } }
分析: 此類是用來建立倫敦的乳酪口味的披薩
public class LDPepperPizza extends Pizza { @Override public void prepare() { setName("倫敦的胡椒pizza"); System.out.println("倫敦的胡椒pizza 準備原材料"); } }
分析: 此類是用來建立倫敦的辣椒口味的披薩
步驟二:建立訂購披薩抽象類
public abstract class OrderPizza { abstract Pizza createPizza(String orderType); public OrderPizza() { do { String orderType = getType(); Pizza pizza = createPizza(orderType); //抽象方法,由工廠子類完成 if (pizza == null){ System.out.println("訂購披薩失敗"); break; } pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); } while (true); } private String getType() { try { BufferedReader strin = new BufferedReader(new InputStreamReader(System.in)); System.out.println("input pizza 種類:"); String str = strin.readLine(); return str; } catch (IOException e) { e.printStackTrace(); return ""; } } }
分析: 此類中定義一個抽象方法createPizza()
, 讓各個工廠子類自己實現,構造器中寫訂購披薩的程式碼邏輯;getType()
方法跟原來的沒有區別。
public class BJOrderPizza extends OrderPizza { @Override Pizza createPizza(String orderType) { Pizza pizza = null; if(orderType.equals("cheese")) { pizza = new BJCheesePizza(); } else if (orderType.equals("pepper")) { pizza = new BJPepperPizza(); } return pizza; } }
分析: 此類用來繼承OrderPizza
類,成為北京地區的訂購披薩分銷商
public class LDOrderPizza extends OrderPizza { @Override Pizza createPizza(String orderType) { Pizza pizza = null; if(orderType.equals("cheese")) { pizza = new LDCheesePizza(); } else if (orderType.equals("pepper")) { pizza = new LDPepperPizza(); } return pizza; } }
分析: 此類也用來繼承OrderPizza
類,成為倫敦地區的訂購披薩分銷商
步驟三:建立執行類
public class PizzaStore { public static void main(String[] args) { String loc = "beijing"; if (loc.equals("beijing")) { new BJOrderPizza(); } else { new LDOrderPizza(); } } }
分析: 假設就是買北京地區的披薩
執行結果:
四、使用抽象工廠
類圖
基本介紹
抽象工廠模式定義了一個interface用於建立相關或有依賴關係的物件簇,而無需指明具體的類
抽象工廠模式可以將簡單工廠模式和工廠方法模式進行整合
從設計層面看,抽象工廠模式就是對簡單工廠模式的改進(或者稱為進一步的抽象)
將工廠抽象成兩層,AbsFactory(抽象工廠) 和 具體實現的工廠子類。程式設計師可以根據建立物件型別使用對應的工廠子類。這樣將單個的簡單工廠類變成了工廠簇,更利於程式碼的維護和擴充套件。
步驟概括
步驟一:建立總工廠介面
public interface AbsFactory { public Pizza createPizza(String orderType); }
分析: 此類是用來讓下面的工廠子類來具體實現
步驟二:建立分工廠
public class BJFactory implements AbsFactory { @Override public Pizza createPizza(String orderType) { Pizza pizza = null; if(orderType.equals("cheese")) { pizza = new BJCheesePizza(); } else if (orderType.equals("pepper")){ pizza = new BJPepperPizza(); } return pizza; } }
分析: 這是工廠子類,用來製作北京的披薩
public class LDFactory implements AbsFactory { @Override 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; } }
分析: 這是工廠子類,用來製作倫敦的披薩
步驟三:建立訂購類
public class OrderPizza { private AbsFactory factory; public OrderPizza(AbsFactory factory) { setFactory(factory); } private void setFactory(AbsFactory factory) { do { this.factory = factory; String orderType = getType(); // factory 可能是北京的工廠子類,也可能是倫敦的工廠子類 Pizza pizza = factory.createPizza(orderType); if (pizza == null) { System.out.println("訂購失敗"); break; } pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); } while (true); } private String getType() { try { BufferedReader strin = new BufferedReader(new InputStreamReader(System.in)); System.out.println("input pizza 種類:"); String str = strin.readLine(); return str; } catch (IOException e) { e.printStackTrace(); return ""; } } }
分析: Pizza pizza = factory.createPizza(orderType);
這一語句主要運用的是java基礎裡面的多型,具體的實現功能交給實現其介面的子類
步驟四:建立執行類
public class PizzaStore { public static void main(String[] args) { new OrderPizza(new LDFactory()); } }
分析: 假設買的是倫敦地區的披薩
執行結果:
總結
1、工廠模式的意義:
將例項化物件的程式碼提取出來,放到一個類中統一管理和維護,達到和主專案的依賴關係的解耦。從而提高專案的擴充套件和維護性。
2、三種工廠模式 (簡單工廠模式、工廠方法模式、抽象工廠模式)
3、設計模式的依賴抽象原則
建立物件例項時,不要直接 new 類, 而是把這個new 類的動作放在一個工廠的方法中,並返回
不要讓類繼承具體類,而是繼承抽象類或者是實現interface(介面)
不要覆蓋基類中已經實現的方法。