一、小案例分析1、功能需求: 實(shí)現(xiàn)一個發(fā)送信息的功能,要便于擴(kuò)展與維護(hù)。 2、小菜雞去實(shí)現(xiàn):(1)定義一個發(fā)送工具的父類(接口),并將各種發(fā)送工具作為子類(實(shí)現(xiàn)類)。 package creative.pattern.factory.noFactory; import java.util.Scanner; /** * 測試類 * */ public class Demo { public static void main(String[] args) { new SendMessage();// 實(shí)例化一個選擇發(fā)送工具的類 } } /** * 定義一個發(fā)送工具的接口 * */ interface Sender { void sendMessage(); } /** * 定義一個短信發(fā)送工具,實(shí)現(xiàn)接口,重寫方法 * */ class ShortMessageSender implements Sender { @Override public void sendMessage() { System.out.println("發(fā)送短信"); } } /** * 定義一個微信發(fā)送工具,實(shí)現(xiàn)接口,重寫方法 * */ class WeChatSender implements Sender { @Override public void sendMessage() { System.out.println("發(fā)送微信"); } } /** * 定義一個郵件發(fā)送工具,實(shí)現(xiàn)接口,重寫方法 * */ class MailSender implements Sender { @Override public void sendMessage() { System.out.println("發(fā)送郵件"); } } /** * 定義一個選擇發(fā)送工具的類 */ class SendMessage { /** * 用于獲取需要發(fā)送信息工具 */ public Sender getSenderType() { System.out.println("輸入發(fā)送工具的類型(1-3):"); System.out.println("1:短信"); System.out.println("2:微信"); System.out.println("3:郵件"); Scanner scanner = new Scanner(System.in); String senderType = scanner.nextLine(); if ("1".equals(senderType)) { return new ShortMessageSender(); } else if ("2".equals(senderType)) { return new WeChatSender(); } else if ("3".equals(senderType)) { return new MailSender(); } else { return null; } } public SendMessage() { do { Sender sender = getSenderType();// 選擇發(fā)送信息的工具 if (sender == null) { System.out.println("歡迎下次使用"); break; } else { sender.sendMessage(); } } while (true); } } (4)代碼分析:
二、簡單工廠模式(SimpleFactory)1、什么是簡單工廠模式:簡單工廠模式屬于創(chuàng)建型模式,不屬于常見的23種常見模式。簡單的講 簡單工廠模式是由一個工廠對象決定創(chuàng)建出哪一類產(chǎn)品的實(shí)例。 2、使用:(1)簡單工廠模式,定義了一個創(chuàng)建對象的類,然后由這個類來封裝實(shí)例化對象的操作。 3、使用簡單工廠模式實(shí)現(xiàn):(1)定義一個發(fā)送工具的父類(接口),并將各種發(fā)送工具作為子類(實(shí)現(xiàn)類)。 package creative.pattern.factory.simpleFactory; import java.util.Scanner; /** * 測試類 * */ public class SimpleFactoryDemo { public static void main(String[] args) { new SendMessage(); } } /** * 定義一個發(fā)送工具的接口 * */ interface Sender { void sendMessage(); } /** * 定義一個短信發(fā)送工具,實(shí)現(xiàn)接口,重寫方法 * */ class ShortMessageSender implements Sender { @Override public void sendMessage() { System.out.println("發(fā)送短信"); } } /** * 定義一個微信發(fā)送工具,實(shí)現(xiàn)接口,重寫方法 * */ class WeChatSender implements Sender { @Override public void sendMessage() { System.out.println("發(fā)送微信"); } } /** * 定義一個郵件發(fā)送工具,實(shí)現(xiàn)接口,重寫方法 * */ class MailSender implements Sender { @Override public void sendMessage() { System.out.println("發(fā)送郵件"); } } /** * 使用簡單工廠模式,管理需要生產(chǎn)的對象 * */ class SimpleFactory { /** * 用于獲取需要發(fā)送信息工具 */ public static Sender createSender() { System.out.println("輸入發(fā)送工具的類型(1-3):"); System.out.println("1:短信"); System.out.println("2:微信"); System.out.println("3:郵件"); Scanner scanner = new Scanner(System.in); String senderType = scanner.nextLine(); if ("1".equals(senderType)) { return new ShortMessageSender(); } else if ("2".equals(senderType)) { return new WeChatSender(); } else if ("3".equals(senderType)) { return new MailSender(); } else { return null; } } } /** * 定義一個選擇發(fā)送工具的類 */ class SendMessage { public SendMessage() { do { Sender sender = SimpleFactory.createSender();// 選擇發(fā)送信息的工具 if (sender == null) { System.out.println("歡迎下次使用"); break; } else { sender.sendMessage(); } } while (true); } } (4)代碼分析:
4、使用靜態(tài)工廠模式實(shí)現(xiàn)(常用形式): 將上例的SimpleFactory 中public Sender createSender()改為 public static Sender createSender()。 public static Sender createSender() { System.out.println("輸入發(fā)送工具的類型(1-3):"); System.out.println("1:短信"); System.out.println("2:微信"); System.out.println("3:郵件"); Scanner scanner = new Scanner(System.in); String senderType = scanner.nextLine(); if ("1".equals(senderType)) { return new ShortMessageSender(); } else if ("2".equals(senderType)) { return new WeChatSender(); } else if ("3".equals(senderType)) { return new MailSender(); } else { return null; } } 三、工廠方法模式1、什么是工廠方法模式:在工廠內(nèi)部定義一個創(chuàng)建對象的抽象方法,由子類去確定要實(shí)例化的對象。簡單的講 工廠方法模式將對象實(shí)例化的操作推遲到子類去實(shí)現(xiàn)??梢钥醋龀橄蠊S模式的一個常見類型。 2、使用工廠模式實(shí)現(xiàn):(1)定義一個發(fā)送工具的父類(接口),并將各種發(fā)送工具作為子類(實(shí)現(xiàn)類)。 package creative.pattern.factory.factoryMethod; import java.util.Scanner; /** * 工廠方法模式測試類 * */ public class factoryMethodDemo { public static void main(String[] args) { new SendMessage(); } } /** * 定義一個發(fā)送工具的接口 * */ interface Sender { void sendMessage(); } /** * 定義一個短信發(fā)送工具,實(shí)現(xiàn)接口,重寫方法 * */ class ShortMessageSender implements Sender { @Override public void sendMessage() { System.out.println("發(fā)送短信"); } } /** * 定義一個微信發(fā)送工具,實(shí)現(xiàn)接口,重寫方法 * */ class WeChatSender implements Sender { @Override public void sendMessage() { System.out.println("發(fā)送微信"); } } /** * 定義一個郵件發(fā)送工具,實(shí)現(xiàn)接口,重寫方法 * */ class MailSender implements Sender { @Override public void sendMessage() { System.out.println("發(fā)送郵件"); } } /** * 使用工廠方法模式,讓子類去創(chuàng)建對象 * */ interface FactoryMethod { Sender sendMessage(); } /** * 短信工廠類,實(shí)現(xiàn)工廠方法類并重寫相關(guān)方法 * */ class ShortMessageFactory implements FactoryMethod { @Override public Sender sendMessage() { return new ShortMessageSender(); } } /** * 微信工廠類,實(shí)現(xiàn)工廠方法類并重寫相關(guān)方法 * */ class WeChatFactory implements FactoryMethod { @Override public Sender sendMessage() { return new WeChatSender(); } } /** * 郵件工廠類,實(shí)現(xiàn)工廠方法類并重寫相關(guān)方法 * */ class MailFactory implements FactoryMethod { @Override public Sender sendMessage() { return new MailSender(); } } /** * 定義一個選擇發(fā)送工具的類 */ class SendMessage { public SendMessage() { do { System.out.println("輸入發(fā)送工具的類型(1-3):"); System.out.println("1:短信"); System.out.println("2:微信"); System.out.println("3:郵件"); Scanner scanner = new Scanner(System.in); String senderType = scanner.nextLine(); if ("1".equals(senderType)) { FactoryMethod factoryMethod = new ShortMessageFactory(); Sender sender = factoryMethod.sendMessage();// 選擇發(fā)送短信 sender.sendMessage(); } else if ("2".equals(senderType)) { FactoryMethod factoryMethod = new WeChatFactory(); Sender sender = factoryMethod.sendMessage();// 選擇發(fā)送微信 sender.sendMessage(); } else if ("3".equals(senderType)) { FactoryMethod factoryMethod = new MailFactory(); Sender sender = factoryMethod.sendMessage();// 選擇發(fā)送郵件 sender.sendMessage(); } else { System.out.println("歡迎下次使用"); break; } } while (true); } } (5)代碼分析:
四、抽象工廠模式1、什么是抽象工廠模式 為創(chuàng)建一組相關(guān)或相互依賴的對象提供一個接口,而且無需指定他們的具體類。 2、抽象工廠模式與工廠方法模式的區(qū)別(1)抽象工廠模式是工廠方法模式的升級版,其針對的是多個產(chǎn)品等級結(jié)構(gòu),即抽象工廠模式所提供的產(chǎn)品是衍生自不同的接口或抽象類。 下圖為抽象工廠模式: 3、舉例: 在之前案例的基礎(chǔ)上,增加一個功能,微信、短信均可以圖片。 package creative.pattern.factory.absFactory; /** * 抽象工廠模式測試類 * */ public class AbsFactoryDemo { public static void main(String[] args) { AbsFactory absFactory = new WeChatFactory(); absFactory.getSender().sendMessage(); absFactory.getSender2().sendMessage(); ((WeChatSender2) absFactory.getSender2()).sendPicture(); AbsFactory absFactory2 = new ShortMessageFactory(); absFactory2.getSender().sendMessage(); absFactory2.getSender2().sendMessage(); ((ShortMessageSender2) absFactory2.getSender2()).sendPicture(); } } /** * 定義一個發(fā)送工具的接口 * */ interface Sender { void sendMessage(); } /** * 定義一個微信發(fā)送工具,實(shí)現(xiàn)接口,重寫方法 * */ class WeChatSender implements Sender { @Override public void sendMessage() { System.out.println("使用微信,發(fā)送短信"); } } /** * 定義一個微信發(fā)送工具,實(shí)現(xiàn)接口,重寫方法,并新增自己的方法 * */ class WeChatSender2 implements Sender { @Override public void sendMessage() { System.out.println("使用微信,發(fā)送短信"); } public void sendPicture() { System.out.println("使用微信,發(fā)送圖片"); } } /** * 定義一個短信發(fā)送工具,實(shí)現(xiàn)接口,重寫方法 * */ class ShortMessageSender implements Sender { @Override public void sendMessage() { System.out.println("使用短信,發(fā)送短信"); } } /** * 定義一個短信發(fā)送工具,實(shí)現(xiàn)接口,重寫方法,并新增自己的方法 * */ class ShortMessageSender2 implements Sender { @Override public void sendMessage() { System.out.println("使用短信,發(fā)送短信"); } public void sendPicture() { System.out.println("使用短信,發(fā)送圖片"); } } /** * 抽象工廠模式 * */ interface AbsFactory { Sender getSender(); Sender getSender2(); } /** * 工廠子類,實(shí)現(xiàn)抽象工廠類,重寫相關(guān)方法, * */ class WeChatFactory implements AbsFactory { @Override public Sender getSender() { return new WeChatSender(); } @Override public Sender getSender2() { return new WeChatSender2(); } } /** * 工廠子類,實(shí)現(xiàn)抽象工廠類,重寫相關(guān)方法, * */ class ShortMessageFactory implements AbsFactory { @Override public Sender getSender() { return new ShortMessageSender(); } @Override public Sender getSender2() { return new ShortMessageSender2(); } } (5)代碼分析: (6)UML圖: 五、JDK中工廠模式舉例(Calendar)1、部分源碼public abstract class Calendar implements Serializable, Cloneable, Comparable<Calendar> { /** * Gets a calendar using the default time zone and locale. The * <code>Calendar</code> returned is based on the current time * in the default time zone with the default * {@link Locale.Category#FORMAT FORMAT} locale. * * @return a Calendar. */ public static Calendar getInstance() { return createCalendar(TimeZone.getDefault(), Locale.getDefault(Locale.Category.FORMAT)); } 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; } } 2、源碼分析Calendar內(nèi)部采用簡單工廠模式進(jìn)行對象的實(shí)例化。其根據(jù)不同的邏輯判斷條件來選擇實(shí)例化具體的對象。
六、總結(jié):1、工廠模式的意義:將實(shí)例化對象的代碼提取出來,放到一個類(工廠類)里面進(jìn)行維護(hù),使其與主項(xiàng)目解耦,提高程序的維護(hù)性與擴(kuò)展性。 2、傳統(tǒng)模式:直接在需要的地方實(shí)例化某對象。擴(kuò)展代碼時,需要在使用到的地方進(jìn)行修改,違反了開閉原則。 3、簡單工廠模式: 在需要用到的地方,調(diào)用工廠類即可,擴(kuò)展代碼時,修改工廠類即可,也違反了開閉原則。 4、工廠方法模式:使用一個工廠類接口與多個工廠實(shí)現(xiàn)類,在不同的工廠實(shí)現(xiàn)類中去實(shí)例化不同的對象。擴(kuò)展代碼時,定義一個工廠實(shí)現(xiàn)類,實(shí)現(xiàn)工廠類接口并重寫相關(guān)方法即可,滿足開閉原則。可以理解為抽象工廠模式的一般形式。 5、抽象工廠模式:可以理解為工廠方法模式的升級版,其在一個接口中定義了一個產(chǎn)品族的處理(多個方法),子類實(shí)現(xiàn)該接口,并重寫相關(guān)方法即可,擴(kuò)展類似于工廠方法模式,滿足開閉原則。 |
|