1.簡單工廠模式
1.1需求入手
????????從需求進行入手,可以更深入的理解什么是設計模式。
????????有一個制作披薩的需求:需要便于擴展披薩的種類,便于維護。
????????1.披薩的種類有很多:GreekPizz,CheesePizz等
????????2.披薩的制作流程:prepare(制作)=> bake(烘烤)=> cut(切開)=> box(打包)
????????3.完成披薩店的訂購功能。
1.2使用傳統的方式進行實現
1.2.1披薩抽象類
????????進行定義抽象披薩類,這個抽象類進行定義了name屬性和抽象方法prepape,這個抽象方法主要是讓繼承的類去實現使用,定義了一些非抽象方法,這些非抽象方法,是派生類通用的代碼,都可以進行使用的這些方法,并且表現出嗯對特征是相同的。
????????即將派生類需要重寫表現出來不同特征的方法在抽象類中直接定義為abstract抽象方法,所有子類表現出來相同特征不需要進行定制化的代碼直接定義為普通方法,放在抽象類中進行使用。
????????這里由于披薩的制作流程,prepare => bake => cut => box,整個過程中只有prepare的過程是不一樣的,其它幾個方法都是一樣的,所以后面的方法都直接在抽象類中進行定義了,這些方法都直接在抽象類中進行實現了邏輯,將prepare定義為abstract方法,方法派生類進行實現。
/*** 披薩類*/
public abstract class Pizza {protected 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~~~");System.out.println("bing go 完成啦~~~");}public void setName(String name) {this.name = name;}}
1.2.2兩個Pizza實現類
/*** GreekPizza*/
public class GreekPizza extends Pizza {@Overridepublic void prepare() {System.out.println("為希臘披薩 準備原材料");}
}
/*** 奶酪披薩*/
public class CheesePizza extends Pizza {@Overridepublic void prepare() {System.out.println("給制作奶酪披薩 準備原材料");}
}
1.2.3定義Pizza下單類
????????這個類中進行封裝了一個getType方法,這個方法主要是進行在控制臺進行接收數據并返回。
????????這個類的主要邏輯封裝在了Constructor中,進行循環在控制臺中進行接收用戶輸入到控制臺中的數據,并進行根據輸入的數據進行采用一些邏輯操作,如果輸入的披薩是有的就進行new一個相應的披薩對象,并進行走相應的制作流程,如果輸入的披薩都不存在,就會break跳出循環,結束點單。
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;/*** 訂購披薩*/
public class OrderPizza {public OrderPizza() {Pizza pizza = null;// 訂購披薩的類型String orderType = null;while (true) {orderType = getType();if (orderType.equals("greek")) {pizza = new GreekPizza();pizza.setName("希臘披薩");} else if (orderType.equals("cheese")) {pizza = new CheesePizza();pizza.setName("奶酪披薩");} else {break;}// 輸出pizza 制作過程pizza.prepare();pizza.bake();pizza.cut();pizza.box();}}private String getType() {BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));System.out.println("input pizza 種類");try {String str = bufferedReader.readLine();return str;} catch (IOException e) {e.printStackTrace();return "";}}}
1.2.4UML類圖
1.3分析傳統方法的問題
1.3.1優缺點的分析
1.3.1.1傳統方式的優點
????????優點就是比較好理解,便于進行操作。
1.3.1.2傳統方式的缺點
????????缺點就是違反了OCP原則(開閉原則),對擴展(提供者)開放,對修改(使用者)關閉,從UML圖中就可以進行分析出來,提供者就是Pizza類的派生類,對擴展開放的意思其實就是Pizza的派生類可以無限進行擴展,代碼底層可以進行更改(只要外部調用的時候表現出來的特征一樣就沒問題),對修改關閉的意思就是,當Pizza進行擴展出新的派生類的時候,十一用者可以進行完美的無縫兼容,調用的方法無需進行改變,這就是OCP原則 => 至少要進行保證盡量少的進行修改代碼。
1.3.1.3缺點的體現
????????假設現在進行增加一個新的Pizza派生類:PepperPizza。
????????此時進行的增加改動是遵循OCP開閉原則,對擴展進行開放。
/*** 胡椒披薩*/
public class PepperPizza extends Pizza {@Overridepublic void prepare() {System.out.println("給制作胡椒披薩 準備原材料");}
}
????????但是如果我們想要在使用者OrderPizza中進行兼容使用,就需要在使用者OrderPizza中進行修改,這樣就違反了OCP原則,對修改沒有進行關閉。
public OrderPizza() {Pizza pizza = null;// 訂購披薩的類型String orderType = null;while (true) {orderType = getType();if (orderType.equals("greek")) {pizza = new GreekPizza();pizza.setName("希臘披薩");} else if (orderType.equals("cheese")) {pizza = new CheesePizza();pizza.setName("奶酪披薩");} else if (orderType.equals("pepper")) {pizza = new PepperPizza();pizza.setName("胡椒披薩");} else {break;}// 輸出pizza 制作過程pizza.prepare();pizza.bake();pizza.cut();pizza.box();}}
1.3.2改進的思路
????????如果進行了擴展,可以接受對代碼進行接單的修改(比如說對一處代碼進行修改),但是我們往往不是只有一個OrderPizza下單的地方,假如說我們這些Pizza還需要在其它的地方進行使用,那么Pizza如果進行了擴展之后,就需要在多處進行修改,這樣就太糟糕了。
????????主要問題:主要問題就是創建Pizza的代碼往往有多處,Pizza進行擴展后需要在多處進行變動修改。
????????思路:將創建Pizza對象封裝到一個類中(工廠類),當我們有新的Pizza類被擴展出的時候,只需要修改這個類即可,其它創建Pizza的代碼就不需要進行修改了 ?=> 簡單工廠模式。
????????簡單工廠模式就是來進行解決這個問題的,將Pizza對象的創建交給簡單工廠類,這樣就將創建Pizza對象的代碼從各個地方進行解耦i。
1.4簡單工廠模式
1.4.1什么是簡單工廠模式
????????1.簡單工廠模式屬于創造性模式,是工廠模式中的一種。簡單工廠模式是由一個工廠對象決定創建出那哪一個產品類的實例。簡單工廠模式是工廠模式家族最簡單實用的模式。
????????2.簡單工廠模式:定義了一個創建對象的類,由這個類來封裝實例化對象的行為(代碼)=> 其實就是將代碼抽離到一個工廠類中,在工廠類中進行創建實例化對象。
????????3.在軟件開發中,當我們會用到大量的創建某種,某類或者某批對象時,就會使用到工廠模式。
1.4.2改進后的UML類設計圖
????????通過UML類設計圖就可以分析出來Pizza派生出去的類都會依賴在SimpleFactory類中,也就是將所有Pizza類型的創建交給SimpleFactory簡單工廠類進行處理,其它的需要創建Pizza對象的類,直接進行將SimpleFactory這個工廠類對象聚合進去使用即可。
????????也就是說將創建Pizza對象的權力交給了SimoleFactory工廠類了,需要創建對象直接找他即可,完成了對象創建的解耦。
1.4.3編寫簡單工廠類
????????其實就是將其它類創建Pizza對象的代碼給集成到SimpleFactory簡單工廠類中,并不僅僅局限于目前類中的createPizza方法,其它方法同樣也是可以進行集成抽離的,我的理解是,只要是用到創建Pizza對象的代碼都可以抽離到SimpleFactory中進行統一維護使用。
????????目前進行定義的createPizza的代碼其實是一個比較健全的根據傳入的類型創建不同Pizza派生類對象的代碼,如果有對應type就會進行創建,如果沒有就不創建,返回一個null。
/*** 簡單工廠類*/
public class SimpleFactory {public Pizza createPizza(String type) {System.out.println("使用簡單工廠模式");Pizza pizza = null;if (type.equals("greek")) {pizza = new GreekPizza();pizza.setName("希臘披薩");} else if (type.equals("cheese")) {pizza = new CheesePizza();pizza.setName("奶酪披薩");} else if (type.equals("pepper")) {pizza = new PepperPizza();pizza.setName("胡椒披薩");}return pizza;}}
1.4.4重塑OrderPizza類
????????其實就是使用聚合的方式將SimpleFactory簡單工廠類集成到OrderPizza,并將創建Pizza對象的邏輯抽取到SimpleFactory中進行完成。
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;/*** 訂購披薩*/
public class OrderPizza {// 定義一個簡單工廠對象private SimpleFactory simpleFactory;private Pizza pizza = null;public void setSimpleFactory(SimpleFactory simpleFactory) {this.simpleFactory = simpleFactory;}public void order() {// 用戶輸出的String orderType = "";// 進行訂購披薩while (true) {orderType = getType();pizza = simpleFactory.createPizza(orderType);// 輸出Pizzaif (pizza != null) {pizza.prepare();pizza.bake();pizza.cut();pizza.box();} else {System.out.println("訂購披薩失敗!!!");break;}}}private String getType() {BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));System.out.println("input pizza 種類");try {String str = bufferedReader.readLine();return str;} catch (IOException e) {e.printStackTrace();return "";}}}
2.工廠方法模式
2.1需求入手
2.1.1需求升級
????????現在進行點披薩的需求再次升級了,主要是下單的奶酪種類進行了進一步細分,客戶在點披薩的時候可以進行點北京的奶酪Pizza,北京的胡椒Pizza或者倫敦的奶酪Pizza,倫敦的胡椒Pizza。
2.1.2思路分析 => 使用簡單工廠模式
????????由于分類進一步細分了,使用一個SimpleFactoiy進行創建不同的Pizza,當然也可以進行根據地域分類的不同,再進行抽象創建出多個SimpleFactory,進行針對不同低于的Pizza使用不同的SimpleFactory。
????????但是考慮項目的規模,以及軟件的可維護性,可擴展性,使用這個方式可能會有很多SimpleFactory,會降低可維護性和擴展性,感覺不是很好。
2.1.3思路分析 => 使用工廠方法模式、
????????使用工廠方法模式可以解決這個問題。
2.2工廠方法模式介紹
2.2.1設計方案
????????將披薩項目的實例化Pizza的功能抽象為抽象方法,在不同的口味點餐子類中具體實現。
2.2.2什么是工廠方法模式
????????定義一個創建對象的抽象方法,由子類決定要實例化的類。工廠方法將對象的實例化推遲到子類。
2.3應用案例
2.3.1UML類圖設計
2.3.2工廠方法抽象類的定義
????????order和getrType都是所有工廠方法實現類都擁有的通用方法,這些方法直接定義在OrderPizza中即可。
????????每個工廠方法實現類的區別主要是在創建Pizza對象的邏輯不一樣,不同的工廠方法實現類負責不同類別的Pizza實例對象的創建,所以要進行定義這個createPizza的抽象方法,讓不同的工廠方法實現類去實現這個abstract方法。
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;/*** 定義抽象方法的工廠 => 方便實現工廠實現實例化的方法*/
public abstract class OrderPizza {// 定義一個抽象, createPizza,public abstract Pizza createPizza(String type);// 下單方法public void order() {// 用戶輸出的String orderType = "";// 進行訂購披薩while (true) {orderType = getType();Pizza pizza = createPizza(orderType);// 輸出Pizzaif (pizza != null) {pizza.prepare();pizza.bake();pizza.cut();pizza.box();} else {System.out.println("訂購披薩失敗!!!");break;}}}private String getType() {BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));System.out.println("input pizza 種類");try {String str = bufferedReader.readLine();return str;} catch (IOException e) {e.printStackTrace();return "";}}}
3.抽象工廠模式
3.1什么是抽象工廠模式
????????1.抽象工廠和模式:定義了一個interface用于創建相關或者有依賴關系的對象簇,而無需指明具體的類。
????????2.抽象工廠模式其實可以將簡單工廠模式和工廠方法模式進行整合。
????????3.從設計層面看,抽象工廠模式就是對簡單工廠模式的改進(或者說是進一步抽象)
????????4.將工廠抽象為兩層:AbsFactory(抽象工廠)和具體實現的工廠子類。程序員可以根據創建對象類型使用對應的工廠子類。這樣單個工廠類就變為了工廠簇,更利于代碼的維護和擴展。
3.2抽象工廠模式案例
3.2.1UML設計類圖
????????這個的設計其實就是定義出了一個AbsFactory接口,抽象出來一個創建實例的工廠方法,讓不同的子類去依賴不同Pizza實現類,去實現相應的方法。
????????然后讓需要進行使用抽象工廠創建相應實例的類中,直接將抽象工廠方法類AbsFactory聚合進去即可,這樣就實現了一層緩沖解耦合。
3.2.2定義抽象工廠方法接口
/*** 抽象工廠的抽象接口*/
public interface AbsFactory {Pizza createPizza(String orderType);}
3.2.3定義抽象工廠方法實現類
/*** 北京抽象工廠實現類*/
public class BJFactory implements AbsFactory {@Overridepublic Pizza createPizza(String orderType) {System.out.println("使用抽象工廠模式");Pizza pizza = null;if (orderType.equals("greek")) {pizza = new BJGreekPizza();pizza.setName("北京希臘披薩");} else if (orderType.equals("cheese")) {pizza = new BJCheesePizza();pizza.setName("北京奶酪披薩");} else if (orderType.equals("pepper")) {pizza = new BJPepperPizza();pizza.setName("北京胡椒披薩");}return pizza;}}
3.2.4創建對象客戶端聚合抽象工廠方法實現類
????????其實就是通過一個字段,定義為抽象接口類型(這樣就可以接收不同類型的抽象工廠實例類對象了)
????????使用setter方法進行給字段設置對應對象 => 從里面就可以體現出聚合。
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;/*** 下單端(使用抽象工廠創建實例)*/
public class OrderPizza {private AbsFactory factory;public void setFactory(AbsFactory factory) {this.factory = factory;}public void order() {// 用戶輸出的String orderType = "";// 進行訂購披薩while (true) {orderType = getType();Pizza pizza = factory.createPizza(orderType);// 輸出Pizzaif (pizza != null) {pizza.prepare();pizza.bake();pizza.cut();pizza.box();} else {System.out.println("訂購披薩失敗!!!");break;}}}private String getType() {BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));System.out.println("input pizza 種類");try {String str = bufferedReader.readLine();return str;} catch (IOException e) {e.printStackTrace();return "";}}}
4.工廠模式在JDK中的應用
4.1Calendar源碼中的應用
????????Calendar的源碼主要是應用了簡單工廠模式,主要是在創建對象的時候進行使用。
????????Calendar中的構造方法被protected化了,所以在外部是無法通過New關鍵字去創建Calendar對象的,但是Calendar類對外暴露了一個getInstance方法進行使用,Calendar類就是通過getInstance方法進行創建對象的。
4.1.1Calendar中創建實例對象的代碼分析
4.1.1.1被封印的構造函數
????????可以看到Calendar方法確實被封印了,方法被標注為了protected,表示這個方法不能在類/派生類的外部進行使用。
/*** Constructs a Calendar with the default time zone* and the default {@link java.util.Locale.Category#FORMAT FORMAT}* locale.* @see TimeZone#getDefault*/
protected Calendar()
{this(TimeZone.getDefaultRef(), Locale.getDefault(Locale.Category.FORMAT));sharedZone = true;
}/*** Constructs a calendar with the specified time zone and locale.** @param zone the time zone to use* @param aLocale the locale for the week data*/
protected Calendar(TimeZone zone, Locale aLocale)
{fields = new int[FIELD_COUNT];isSet = new boolean[FIELD_COUNT];stamp = new int[FIELD_COUNT];this.zone = zone;setWeekCountData(aLocale);
}
4.1.1.2getInstancer方法創建對象
????????Calendar使用getIntance進行讓外部創建對象,這就是Calendar進行暴露在外部創建對象的方法(getInstance方法)
????????Calendar主要也是在里面進行使用了簡單工廠模式,進行創建對象。
????????接下來就來分析一下getInstance的源碼。
/*** 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));
}/*** Gets a calendar using the specified time zone and default locale.* The <code>Calendar</code> returned is based on the current time* in the given time zone with the default* {@link Locale.Category#FORMAT FORMAT} locale.** @param zone the time zone to use* @return a Calendar.*/
public static Calendar getInstance(TimeZone zone)
{return createCalendar(zone, Locale.getDefault(Locale.Category.FORMAT));
}/*** Gets a calendar using the default time zone and specified locale.* The <code>Calendar</code> returned is based on the current time* in the default time zone with the given locale.** @param aLocale the locale for the week data* @return a Calendar.*/
public static Calendar getInstance(Locale aLocale)
{return createCalendar(TimeZone.getDefault(), aLocale);
}/*** Gets a calendar with the specified time zone and locale.* The <code>Calendar</code> returned is based on the current time* in the given time zone with the given locale.** @param zone the time zone to use* @param aLocale the locale for the week data* @return a Calendar.*/
public static Calendar getInstance(TimeZone zone,Locale aLocale)
{return createCalendar(zone, aLocale);
}
4.1.2分析getInstance方法
????????就從最簡單常用的無參getInstance方法進行分析。
????????可以看見其中調用了關鍵方法createCalendar,這個方法是實例化對象的關鍵。
public static Calendar getInstance()
{return createCalendar(TimeZone.getDefault(), Locale.getDefault(Locale.Category.FORMAT));
}
????????Calendar整體源碼還是比較清晰的,根據對源碼的追溯,其中最重要的就是兩點:
????????1.CalendarProvider對象,這個對象還是很關鍵的,在createCalendar的流程中進行獲取到了這個對象。
????????2.調用CalendarProvider對象中的getInstance方法進行創建了一個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;
}
4.1.3分析CalendarProvider
????????這里不用去關心createCalendar是怎么獲取到的,只需要關心怎么用的CalendarProvider對象,內部的原理是什么即可。
????????CalendarProvider其實是一個抽象類,主要是進行定義了一個關鍵的abstract方法getInstance,這個方法返回的是一個Calendar,主要進行用于創建Calendar實例。
/*** An abstract class for service providers that* provide instances of the* {@link java.util.Calendar Calendar} class.** @since 1.8*/
public abstract class CalendarProvider extends LocaleServiceProvider {/*** Sole constructor. (For invocation by subclass constructors, typically* implicit.)*/protected CalendarProvider() {}/*** Returns a new <code>Calendar</code> instance for the* specified locale.** @param zone the time zone* @param locale the desired locale* @exception NullPointerException if <code>locale</code> is null* @exception IllegalArgumentException if <code>locale</code> isn't* one of the locales returned from* {@link java.util.spi.LocaleServiceProvider#getAvailableLocales()* getAvailableLocales()}.* @return a <code>Calendar</code> instance.* @see java.util.Calendar#getInstance(java.util.Locale)*/public abstract Calendar getInstance(TimeZone zone, Locale locale);
}
????????CalendarProviderImpl進行實現了CalendarProvider抽象類,其中最主要的是進行實現了gtetInstance方法。
????????會發現getInstance方法進行完成了將Calendar實例化并返回出去的任務。
/*** Concrete implementation of the {@link sun.util.spi.CalendarProvider* CalendarProvider} class for the JRE LocaleProviderAdapter.** @author Naoto Sato*/
public class CalendarProviderImpl extends CalendarProvider implements AvailableLanguageTags {private final LocaleProviderAdapter.Type type;private final Set<String> langtags;public CalendarProviderImpl(LocaleProviderAdapter.Type type, Set<String> langtags) {this.type = type;this.langtags = langtags;}/*** Returns an array of all locales for which this locale service provider* can provide localized objects or names.** @return An array of all locales for which this locale service provider* can provide localized objects or names.*/@Overridepublic Locale[] getAvailableLocales() {return LocaleProviderAdapter.toLocaleArray(langtags);}@Overridepublic boolean isSupportedLocale(Locale locale) {// Support any locales.return true;}/*** Returns a new <code>Calendar</code> instance for the* specified locale.** @param zone the time zone* @param locale the desired locale* @exception NullPointerException if <code>locale</code> is null* @exception IllegalArgumentException if <code>locale</code> isn't* one of the locales returned from* {@link java.util.spi.LocaleServiceProvider#getAvailableLocales()* getAvailableLocales()}.* @return a <code>Calendar</code> instance.* @see java.util.Calendar#getInstance(java.util.Locale)*/@Overridepublic Calendar getInstance(TimeZone zone, Locale locale) {return new Calendar.Builder().setLocale(locale).setTimeZone(zone).setInstant(System.currentTimeMillis()).build();}@Overridepublic Set<String> getAvailableLanguageTags() {return langtags;}
}
4.1.4圖解源碼 => 根據UML類圖理解Calendar實例化設計
????????去理解源碼中的設計思想單單靠Debug和文字講解是比較抽象的,畫出來一個UML類圖進行理解會比較直觀,沒有這么抽象。
????????現在我將代碼進行梳理了出來,Calendar是被依賴的類,也是進行調用創建Calendar實例對象的客戶端,CalendarProviderImpl其實就是進行創建Calendar實例對象的工廠類,所以說這里進行使用的就是簡單工廠設計模式。
????????將創建類的能力抽離到了工廠類中。
4.2Iterator源碼中的應用
4.2.1簡要理解
????????Iterator是在Collection整個體系中進行使用了這個Iterator,JDK整個Collection體系中進行使用到了Iterator,在這個集合體系中任何一個類型的集合都是一個工廠,接口和抽象類是抽象工廠,普通類是實際的生產對象的工廠,工廠進行創建的對象是Iteator。
????????理清幾個重要的關系:
????????抽象工廠(定義抽象方法的接口/抽象類):接口/抽象類
????????實例工廠(實際執行創建實例的工廠類):實現接口/繼承抽象類的實例類
????????實例化的對象:Iterator以及其實現類(整個體系)
4.2.2UML類圖
5.三大工廠模式小結
5.1工廠模式的意義
????????將實例化的代碼提取出來,放到一個類中進行統一管理和維護,達到和主項目依賴關系的解耦。從而提高項目的擴展性和維護性。
5.2三種工廠模式
????????1.簡單工廠模式
????????就是將一個抽象類型的類,其所有派生類實例化對象的創建均抽取到一個工廠類中,使用工廠類完成所有類實例化對象的創建。
????????實現了創建對象代碼的解耦,將實例化對象的邏輯全部抽取到工廠類中。
????????2.工廠方法模式
????????就是定義一個抽象工廠類,使用這個抽象工廠派生出各種各樣的工廠實現類,進行對不同種類的對象進行實例化,客戶端可以根據自己的需求去選擇不同的工廠實現類,調用創建自己需要的對象。
????????就是對簡單工廠進行按不同類型對象的創建職責進行了進一步的拆分,不同類型的對象采用不同工廠進行創建,提高了擴展性和可維護性,適合大型項目進行使用。
????????3.抽象工廠模式
????????抽象工廠模式就是定義了一個抽象方法,在抽象中進行定義實例化對象的方法,工廠進行實現這個接口,實現工廠中創建哪些對象的邏輯,客戶端需要進行創建對象的時候,注入這個工廠進行創建即可,需要替換的時候與,注入其它工廠即可(注入的類型為接口,方便進行替換為其它實現工廠)
5.3設計模式的依賴抽象原則
????????其實三大工廠設計模式都是進行遵循設計模式的依賴抽象原則,比如說簡單工廠中,工廠類就是一層抽象(抽象程度弱),工廠方法模式中的抽象工廠類也是一層抽象(使用抽象類進行架構設計,抽象程度強),抽象工廠設計模式也是一層抽象,使用接口進行抽象出相應的對象實例化的抽象方法,接口就是相應的抽象(抽象能力強)
5.4工廠模式總結
5.4.1創建對象實例小結
????????創建對象實例時,不要直接new實例,而是將這個new類的動作放在一個工廠方法中,并進行返回這個對象實例。
5.4.2實例化對象類體系的設定
????????實例化對象的類體系最好是進行抽象出來一個抽象類或者接口進行實現/繼承,不要讓工廠創建的對象的類型是類繼承的具體的類的類型,要化具體為抽象,類型應該是抽象的,不應該是具體的。