java設計模式2-工廠模式
工廠模式
工廠模式屬於建立型模式.提供了一種建立物件的最佳方式.
介紹
定義一個建立物件的介面,讓其子類自己決定例項化哪一工廠類,工廠模式使其建立過程延遲到子類進行.
應用例項一
您需要一輛汽車,可以直接從工廠裡面提貨,而不用去管這倆汽車是怎麼做出來的,如果想新增一個產品,只有擴充套件一個工廠類就可以,遮蔽了產品的具體實現,呼叫者只關心產品的介面.
看一個具體需求
如一個披薩專案:要便於披薩種類的擴充套件、要便於維護
1、披薩的種類很多()
2、披薩的製作有prepare、bake、cut、box
3、完成披薩店訂購功能
使用傳統方法
編寫OrderPizza.java去訂購需要的各種Pizza
public class OrderPizza { public OrderPizza() { Pizza pizza = null; String orderType; do { orderType = getType(); if (orderType.equals("greek")) { pizza = new GreekPizza(); pizza.setName("GreekPizza...."); }else if (orderType.equals("cheese")) { pizza = new CheesePizza(); pizza.setName("cheese...."); } else if (orderType.equals("pepper")) { pizza = new PepperPizza(); pizza.setName("PepperPizza...."); } else {break; } pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); } while (true); } private String getType() { Scanner scanner = new Scanner(System.in); System.out.println("請輸入相應訂購的型別"); String orderType = scanner.nextLine(); return orderType; } }
傳統方式的優缺點
1、優點是比較好理解,簡單易操作
2、缺點是違反了設計模式的ocp原則,即對擴充套件開發,對修改關閉.當我們給類增加新功能時,儘量不修改程式碼,
比如我們要增加新Pizza時,需要作如下修改
orderType = getType(); if (orderType.equals("greek")) { pizza = new GreekPizza(); pizza.setName("GreekPizza...."); } else if (orderType.equals("cheese")) { pizza = new CheesePizza(); pizza.setName("cheese...."); } else if (orderType.equals("pepper")) { pizza = new PepperPizza(); pizza.setName("PepperPizza...."); } else { break; }
改進思路分析
分析:修改程式碼可以接受,但是如果我們在其他地方也有建立Pizza的程式碼,就意味著,也需要修改,而建立的程式碼,往往有多處.
思路:把建立Pizza物件封裝到一個類中,這樣我們有新的Pizza種類時,只需要修改該類就可,其他有建立物件的程式碼就不需要修改了--》簡單工廠模式
基本介紹
1、簡單工廠模式是屬於建立型模式,是工廠模式的一種.簡單工廠模式是由一個工廠物件決定創建出哪一種產品類的例項.簡單工廠是工廠模式家族中最簡單實用的模式
2、簡單工廠模式:定義了一個建立物件的類,由這個類來封裝例項物件的行為
在軟體開發中,我們會用到大量的建立某種、某類或者某批物件時,就會使用到工廠模式.
使用簡單工廠模式
簡單工廠模式的設計方法:定義一個可以例項化Pizza物件的類,封裝建立物件的程式碼.
public class SimpleFactory { // orderType 返回對應的 Pizza 物件 public Pizza createPizza(String orderType) { Pizza pizza = null; System.out.println("使用簡單工廠模式"); if (orderType.equals("greek")){ pizza = new GreekPizza(); pizza.setName("GreekPizza////"); }else if (orderType.equals("cheese")){ pizza = new CheesePizza(); pizza.setName("CheesePizza////"); }else if (orderType.equals("pepper")){ pizza = new PepperPizza(); pizza.setName("PepperPizza////"); } return pizza; }
orderPizza
public class OrderPizza { SimpleFactory simpleFactory; Pizza pizza = null; public OrderPizza(SimpleFactory simpleFactory) { setFactory(simpleFactory); } private void setFactory(SimpleFactory simpleFactory) { this.simpleFactory = simpleFactory; String orderType; do { orderType = getType(); pizza = this.simpleFactory.createPizza(orderType); if (pizza != null) { pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); } else { System.out.println(" 訂購披薩失敗 "); break; } } while (true); } private String getType() { try { BufferedReader string = new BufferedReader(new InputStreamReader(System.in)); System.out.println("input pizza 種類:"); String str = string.readLine(); return str; } catch (IOException e) { e.printStackTrace(); return ""; } } }
工廠方法模式
看一個新的需求
客戶在點披薩時,可以點不同口味的披薩,比如,北京的乳酪pizza、北京的胡椒pizza或者是倫敦的乳酪pizza、倫敦的胡椒pizza
思路1
使用簡單工廠模式,建立不同的簡單工廠類,比如BJPizzaSimpleFactory、LDPizzaSimpeFactory等等.從當前這個案例,也是可以的.但是考慮到專案的規模,以及軟體的可維護性、可擴充套件性並不是特別好.
思路2
使用工廠方法模式
基本介紹
1、工廠方法模式設計方法:將披薩專案的例項化功能抽象成抽象方法,在不同的口味點餐子類中具體實現.
2、工廠方法模式:定義了一個建立物件的抽象方法,由子類決定要例項化的類.工廠方法模式將物件的例項化推遲到子類
工廠方法模式應用案例
1、披薩專案新的需求:客戶在點披薩時,可以點不同口味的披薩,比如北京的乳酪pizza、北京的胡椒pizza,還可以選不同地區的pizza,倫敦乳酪pizza、倫敦的胡椒pizza
思路分析圖解
OrderPizza
public abstract class OrderPizza { abstract Pizza createPizza(String orderType); OrderPizza() { Pizza pizza = null; String orderType = null; do { orderType = getType(); pizza = createPizza(orderType); 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 ""; } } }
BJOrderPizza
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; } }
LDOrderPizza
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; } }
抽象工廠模式
基本介紹
1、抽象工廠模式:定義了一個interface用於建立相關或有依賴關係的物件簇,而無需指明具體的類.
2、抽象工廠模式可以將簡單工廠模式和工廠方法模式進行整合
3、從設計層面看,抽象工廠模式就是對簡單工廠模式的改進(或者稱為進一步的抽象)
將工廠抽象成兩層,AbsFactory和具體實現的工廠子類.程式設計師可以根據建立物件型別使用對應的工廠子類.這樣將單個的簡單工廠類變成了工廠簇,更利於程式碼的維護和擴充套件
抽象工廠模式應用例項
public interface AbsFactory { public Pizza createPizza(String orderType); } public class BJFactory implements AbsFactory { @Override public Pizza createPizza(String orderType) { System.out.println("~使用的是抽象工廠模式~"); 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) { System.out.println("~使用的是抽象工廠模式~"); Pizza pizza = null; if (orderType.equals("cheese")) { pizza = new LDCheesePizza(); } else if (orderType.equals("pepper")) { pizza = new LDPepperPizza(); } return pizza; } } public class OrderPizza { AbsFactory factory; // 構造器 public OrderPizza(AbsFactory factory) { setFactory(factory); } private void setFactory(AbsFactory factory) { Pizza pizza = null; // 使用者輸入 String orderType = ""; this.factory = factory; do { orderType = getType(); // factory 可能是北京的工廠子類,也可能是倫敦的工廠子類 pizza = factory.createPizza(orderType); // 訂購 ok pizza.prepare(); if (pizza != null) { 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 ""; } } }
工廠模式在JDK-Calendar應用的原始碼分析
1、JDK中的Calendar類中,就使用了簡單工廠模式
private static Calendar createCalendar(TimeZone zone, Locale aLocale) { CalendarProvider provider = LocaleProviderAdapter.getAdapter(CalendarProvider.class, aLocale) .getCalendarProvider(); if (provider != null) { try { return provider.getInstance(zone, aLocale); } catch (IllegalArgumentException iae) { // fall back to the default instantiation } } Calendar cal = null; if (aLocale.hasExtensions()) { String caltype = aLocale.getUnicodeLocaleType("ca"); if (caltype != null) { switch (caltype) { case "buddhist": cal = new BuddhistCalendar(zone, aLocale); break; case "japanese": cal = new JapaneseImperialCalendar(zone, aLocale); break; case "gregory": cal = new GregorianCalendar(zone, aLocale); break; } } } if (cal == null) { // If no known calendar type is explicitly specified, // perform the traditional way to create a Calendar: // create a BuddhistCalendar for th_TH locale, // a JapaneseImperialCalendar for ja_JP_JP locale, or // a GregorianCalendar for any other locales. // NOTE: The language, country and variant strings are interned. if (aLocale.getLanguage() == "th" && aLocale.getCountry() == "TH") { cal = new BuddhistCalendar(zone, aLocale); } else if (aLocale.getVariant() == "JP" && aLocale.getLanguage() == "ja" && aLocale.getCountry() == "JP") { cal = new JapaneseImperialCalendar(zone, aLocale); } else { cal = new GregorianCalendar(zone, aLocale); } } return cal; }
工廠模式小結
1、工廠模式的意義
a)將例項化物件的程式碼提取出來,放到一個類中統一管理和維護,達到和主專案的依賴關係的解耦.從而提高專案的擴充套件和維護性.
2、三種工廠模式(簡單工廠模式、工廠方法模式、抽象工廠模式)
a)簡單工廠模式:
簡單工廠模式是由一個工廠物件決定創建出哪一種產品類的例項,將建立物件的程式碼提取到一個工廠中(simpleFactory),保證單一原則.
b)工廠方法模式:將訂購物件的程式碼抽象為方法,提高可維護性、可擴充套件性
c)抽象工廠模式:將建立物件的方法抽象,並將工廠抽象,進一步提高可維護性、可擴充套件性
d) 工廠方法跟抽象工廠區別是抽象工廠抽象了兩層(介面+具體實現子類,而工廠方法是抽象類出現方法)
3、設計模式的依賴抽象原則
1、建立物件例項時,不要直接new類,而是把這個new類的動作放在一個工廠的方法中,並返回.有的書上說,變數不要直接持有具體類的引用.
2、不要讓類繼承具體類,而是繼承抽象類或者實現介面
3、不要覆蓋基類中已經實現的方法