三大工廠設計模式

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實例化對象類體系的設定

????????實例化對象的類體系最好是進行抽象出來一個抽象類或者接口進行實現/繼承,不要讓工廠創建的對象的類型是類繼承的具體的類的類型,要化具體為抽象,類型應該是抽象的,不應該是具體的。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/89944.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/89944.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/89944.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

SpringBoot--Mapper XML 和 Mapper 接口在不同包

&#x1f9e9; 背景說明在 Spring Boot 中&#xff0c;MyBatis 默認要求 Mapper 接口和 XML 文件位于相同包路徑。 但在實際項目中&#xff0c;為了模塊化或結構清晰&#xff0c;常將 XML 放在 resources/mybatis/... 下&#xff0c;這種做法就必須進行額外配置。&#x1f4c1;…

公交車客流人數統計管理解決方案:智能化技術與高效運營實踐

1. 引言公交車作為城市公共交通的核心組成部分&#xff0c;其客流數據的精準統計與管理直接影響運營效率、調度優化和乘客體驗。傳統的人工統計方式效率低、誤差大&#xff0c;難以滿足現代智慧交通的需求。隨著人工智能&#xff08;AI&#xff09;、物聯網&#xff08;IoT&…

正則表達式完全指南:從入門到實戰

目錄 一、什么是正則表達式&#xff1f; 二、基礎語法速查表 三、進階特性 1.分組與捕獲 2.非捕獲分組 3.前瞻與后顧 4.貪婪與懶惰匹配 四、實戰案例 案例1&#xff1a;驗證手機號 案例2&#xff1a;提取網頁中所有鏈接 案例3&#xff1a;密碼強度驗證 一、什么是正…

SmartETL循環流程的設計與應用

1. 引言 **檢索增強生成&#xff08;RAG&#xff09;**是指通過檢索對大模型生成進行增強的技術&#xff0c;通過充分利用信息檢索&#xff08;尤其是語義檢索&#xff09;相關技術&#xff0c;實現大模型快速擴展最新知識、有效減少幻覺的能力。主流RAG框架包括問題理解、知識…

uni-app開發小程序,根據圖片提取主題色值

需求&#xff0c;在頁面根據傳入的圖片提取圖片主色值并用來設置區塊背景色<template><view class"icon-container"><view class"sport-icon" :style"{ backgroundColor: mainColor }"><image :src"/static/images/sp…

ESP32-Cam三腳架機器人:DIY你的智能移動監控平臺

項目概述 在物聯網與機器人技術融合發展的今天&#xff0c;基于ESP32的創意項目層出不窮。今天為大家介紹一款極具創新性的ESP32-Cam三腳架機器人&#xff08;Dodge&#xff09;&#xff0c;它將傳統三腳架結構與智能監控功能完美結合&#xff0c;通過巧妙的機械設計和開源硬件…

Kotlin集合過濾

過濾操作 在處理集合時&#xff0c;根據特定條件過濾集合或檢查集合中是否包含符合特定條件的元素是軟件開發中的常見任務。為了解決這個問題&#xff0c;我們可以使用 Kotlin 中實現的函數式 API。 在本主題中&#xff0c;我們將介紹如何使用謂詞過濾集合&#xff0c;并獲得滿…

14.8 LLaMA2-7B×Dolly-15K實戰:從準確率63%到89%,如何用優質數據讓大模型性能飆升42%?

LLaMA2-7BDolly-15K實戰:從準確率63%到89%,如何用優質數據讓大模型性能飆升42%? 在大模型微調中,“數據質量”往往比“數據數量”更能決定最終效果。Databricks發布的Dolly-15K數據集以“全人工標注+多維度校驗”的特點,成為指令微調的“黃金樣本”——用它微調后的LLaMA…

OpenCV中常用特征提取算法(SURF、ORB、SIFT和AKAZE)用法示例(C++和Python)

OpenCV 中提供了多種常用的特征提取算法&#xff0c;廣泛應用于圖像匹配、拼接、SLAM、物體識別等任務。以下是 OpenCV 中幾個主流特征提取算法的 用法總結與代碼示例&#xff0c;涵蓋 C 和 Python 兩個版本。常用特征提取算法列表算法特點是否需額外模塊SIFT&#xff08;尺度不…

復雜度+包裝類型+泛型

什么是集合框架什么是數據結構什么是算法時間復雜度與空間復雜度的概念時間復雜度的表達方式時間復雜度的大 O 的漸近表示法時間復雜度函數的大小排序包裝類和泛型基本數據類型和對應的包裝類型包裝類型出現的原因什么叫做裝箱&#xff08;裝包&#xff09;和拆箱&#xff08;拆…

硬件設計學習DAY15——自舉電容:MOSFET高端驅動的核心奧秘

每日更新教程&#xff0c;評論區答疑解惑&#xff0c;小白也能變大神&#xff01;" 目錄 一.自舉電容 1.自舉電容的作用 2.自舉電路原理 3.工作過程分析 4.實際應用中的問題 5.關鍵要點 二.自舉電容實現MOSFET高端驅動 2.1MOSFET半橋高端驅動的基本原理 2.2自舉電…

【SpringAI實戰】實現仿DeepSeek頁面對話機器人

一、實現效果 二、代碼實現 2.1 后端代碼 2.2 前端代碼 一、實現效果 可以保存聊天記錄與會話記錄 二、代碼實現 2.1 后端代碼 pom.xml <!-- 繼承Spring Boot父POM&#xff0c;提供默認依賴管理 --><parent><groupId>org.springframework.boot</grou…

RedisJSON 指令精講JSON.STRLEN 高效統計字符串長度

1 場景與價值 在日志累加、指標采集、消息追蹤等場景中&#xff0c;我們常需快速判斷某個字符串字段“到底有多長”&#xff0c;以便&#xff1a; 阻止過大日志&#xff1a;若長度超限則截斷或歸檔&#xff1b;動態分桶&#xff1a;按長度選擇不同存儲策略&#xff1b;性能監控…

大數據量查詢計算引發數據庫CPU告警問題復盤

大數據量查詢計算引發數據庫CPU告警問題復盤一、背景二、根因分析三、解決方案方案1&#xff1a;多線程緩存方案2&#xff1a;利用中間表緩存四、總結一、背景 2025年7月份某天&#xff0c;CDP系統每天不定時推送我們的Portal服務&#xff0c;生產環境運營看板會展示統計數據&…

2025最新版虛幻引擎5(UE5)C++入門教程:前言——你的隨身教程和學習筆記

大家好&#xff0c;我是開發游戲的老王&#xff0c;一名高校教師&#xff0c;我主講游戲開發已有十余年時間&#xff0c;通過我的博客大家應該可以了解我所涉獵的游戲技術范疇非常廣泛&#xff0c;除了Unreal,Unity,Godot等主流游戲引擎&#xff0c;還包括Blender、Houdini、3D…

(3)重定向 | 時間相關指令 | 文件查找 | 打包與壓縮

Ⅰ . 初始重定向01 輸出重定向 >在上一節中我們為了方便講解 head 和 tail 指令&#xff0c;我們用到了 > 去生成了一千行文本。通過 > 將生成的一千行文本寫入到了 large.txt 中……我們現在來正式介紹一下&#xff1a;$ echo "內容" > [目標] 本來應…

DTH11測量溫濕度學習(第十一天)

&#x1f468;?&#x1f4bb;個人主頁&#xff1a;開發者-削好皮的Pineapple! &#x1f468;?&#x1f4bb; hello 歡迎 點贊&#x1f44d; 收藏? 留言&#x1f4dd; 加關注?! &#x1f468;?&#x1f4bb; 本文由 削好皮的Pineapple! 原創 &#x1f468;?&#x1f4…

Go語言初識--標識符 可見性

Go語言初識–標識符 可見性 和C語言相似&#xff0c;go語言的基本組成有&#xff1a; 包聲明&#xff0c;編寫源文件時&#xff0c;必須在非注釋的第一行指明這個文件屬于哪個包&#xff0c;如package main。引入包&#xff0c;其實就是告訴Go 編譯器這個程序需要使用的包&…

Python實例之畫小豬佩奇

效果圖&#xff1a;python代碼以及解釋&#xff0c;沒有運用模塊。 """ 繪制小豬佩奇 """ from turtle import *def nose(x,y):"""畫鼻子"""penup()# 將海龜移動到指定的坐標goto(x,y)pendown()# 設置海龜的方向&…

Unity筆記——事件中心

事件中心是什么事件中心是 Unity 游戲開發中常用的架構設計&#xff0c;它基于觀察者模式 或 發布-訂閱模式&#xff0c;通過委托和事件構建的一種消息管理系統。主要用于降低代碼耦合度&#xff0c;實現模塊間的松耦合通信的消息處理系統能大幅提升代碼的可維護性和擴展性&…