getinstance方法详解_二、设计模式总览及工厂模式详解
二、架構師內功心法之設計模式
2.架構師內功心法之設計模式
2.1.課程目標
1、通過對本章內容的學習,了解設計模式的由來。
2、介紹設計模式能幫我們解決哪些問題。
3、剖析工廠模式的歷史由來及應用場景。
2.2.內容定位
不用設計模式并非不可以,但是用好設計模式能幫助我們更好地解決實際問題,設計模式最重要的 是解耦。設計模式天天都在用,但自己卻無感知。我們把設計模式作為一個專題,主要是學習設計模式 是如何總結經驗的,把經驗為自己所用。學設計模式也是鍛煉將業務需求轉換技術實現的一種非常有效 的方式。
2.3.回顧軟件設計原則
設計原則解釋開閉原則對擴展開放,對修改關閉依賴倒置原則通過抽象使各個類或者模塊不相互影響,實現松耦合。單一職責原則一個類、接口、方法只做一件事。接口隔離原則盡量保證接口的純潔性,客戶端不應該依賴不需要的接口。迪米特法則又叫最少知道原則,一個類對其所依賴的類知道得越少越好。里氏替換原則子類可以擴展父類的功能但不能改變父類原有的功能。合成復用原則盡量使用對象組合、聚合,而不使用繼承關系達到代碼復用的目的。
2.4.設計模式總覽
寫出優雅的代碼
更好地重構項目
經典框架都在用設計模式解決問題
Spring就是一個把設計模式用得淋漓盡致的經典框架,其實從類的命名就能看出來,我來一一列舉:
設計模式名稱舉例工廠模式BeanFactory裝飾器模式BeanWrapper代理模式AopProxy委派模式DispatcherServlet策略模式HandlerMapping適配器模式HandlerAdapter模板模式JdbcTemplate觀察者模式ContextLoaderListener
我們的課程中,會圍繞 Spring 的 IOC、AOP、MVC、JDBC 這樣的思路展開,根據其設計類型來設計講解順序:
類型名稱英文創建型模式工廠模式Factory Pattern單例模式Singleton Pattern原型模式Prototype Pattern結構型模式適配器模式Adapter Pattern裝飾器模式Decorator Patter代理模式Proxy Pattern行為性模式策略模式Strategy Pattern模板模式Template Pattern委派模式Delegate Pattern觀察者模式Observer Pattern
3.工廠模式詳解
3.1.工廠模式的歷史由來
原始社會自給自足(沒有工廠)、農耕社會小作坊(簡單工廠,民間酒 坊)、工業革命流水線(工廠方法,自產自銷)、現代產業鏈代工廠(抽象工廠,富士康)
3.2.簡單工廠模式
3.2.1.定義
簡單工廠模式(Simple Factory Pattern)是指由一個工廠對象決定創建出哪一種產品類的實例, 但它不屬于GOF 23種設計模式。簡單工廠適用于工廠類負責創建的對象較少的場景,且客戶端只需要 傳入工廠類的參數,對于如何創建對象的邏輯不需要關心。
3.2.2.demo
public class SimpleFactoryTest {public static void main(String[] args) {CourseFactory factory = new CourseFactory();ICourse course = factory.create(JavaCourse.class);course.record();}
}public class JavaCourse implements ICourse {public void record() {System.out.println("錄制Java課程");}
}public class CourseFactory {public ICourse create(Class<? extends ICourse> clazz){// 反射try {if (null != clazz) {return clazz.newInstance();}}catch (Exception e){e.printStackTrace();}return null;}
}3.2.3.源碼
- Calendar.getInstance()
- LoggerFactory.getLogger()
簡單工廠模式在 JDK 源碼也是無處不在,現在我們來舉個例子,例如 Calendar 類,看 Calendar.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;}還有一個大家經常使用的 logback,我們可以看到 LoggerFactory 中有多個重載的方法 getLogger():
public static Logger getLogger(String name) {ILoggerFactory iLoggerFactory = getILoggerFactory();return iLoggerFactory.getLogger(name);}public static Logger getLogger(Class clazz) {return getLogger(clazz.getName());}3.2.4.優缺點
- 優點
- 簡單
- 缺點
- 工廠類的職責相對過重,不易于擴展過于復雜的產品結構。
3.3.工廠方法模式
3.3.1.定義
工廠方法模式(Factory Method Pattern)是指定義一個創建對象的接口,但讓實現這個接口的類 來決定實例化哪個類,工廠方法讓類的實例化推遲到子類中進行。在工廠方法模式中用戶只需要關心所 需產品對應的工廠,無須關心創建細節,而且加入新的產品符合開閉原則。
3.3.2.demo
public class FactoryMethodTest {public static void main(String[] args) {// Python課程工廠ICourseFactory factory = new PythonCourseFactory();ICourse course = factory.create();course.record();// Java課程工廠factory = new JavaCourseFactory();course = factory.create();course.record();}
}public class JavaCourseFactory implements ICourseFactory {public ICourse create() {return new JavaCourse();}
}public interface ICourseFactory {ICourse create();
}public class JavaCourse implements ICourse {public void record() {System.out.println("錄制Java課程");}
}public interface ICourse {void record();
}3.3.3.源碼
ApplicationContext就是工廠方法模式
再來看看logback中工廠方法模式的應用,看看類圖就OK了:
3.3.4.優缺點
- 工廠方法適用于以下場景:
- 創建對象需要大量重復的代碼。
- 客戶端(應用層)不依賴于產品類實例如何被創建、實現等細節。
- 一個類通過其子類來指定創建哪個對象。
- 工廠方法也有缺點:
- 類的個數容易過多,增加復雜度。
- 增加了系統的抽象性和理解難度。
3.4.抽象工廠模式
3.4.1.定義
抽象工廠模式(AbastractFactory Pattern)是指提供一個創建一系列相關或相互依賴對象的接口,無須指定他們具體的類。客戶端(應用層)不依賴于產品類實例如何被創建、實現等細節,強調的是一 系列相關的產品對象(屬于同一產品族)一起使用創建對象需要大量重復的代碼。需要提供一個產品類 的庫,所有的產品以同樣的接口出現,從而使客戶端不依賴于具體實現。
講解抽象工廠之前,我們要了解兩個概念產品等級結構和產品族,看下面的圖:
從上圖中看出有正方形,圓形和菱形三種圖形,相同顏色深淺的就代表同一個產品族,相同形狀的代表 同一個產品等級結構。同樣可以從生活中來舉例,比如,美的電器生產多種家用電器。那么上圖中,顏 色最深的正方形就代表美的洗衣機、顏色最深的圓形代表美的空調、顏色最深的菱形代表美的熱水器, 顏色最深的一排都屬于美的品牌,都是美的電器這個產品族。再看最右側的菱形,顏色最深的我們指定 了代表美的熱水器,那么第二排顏色稍微淺一點的菱形,代表海信的熱水器。同理,同一產品結構下還 有格力熱水器,格力空調,格力洗衣機。
再看下面的這張圖,最左側的小房子我們就認為具體的工廠,有美的工廠,有海信工廠,有格力工廠。 每個品牌的工廠都生產洗衣機、熱水器和空調。
3.4.2.demo
public class AbstractFactoryTest {public static void main(String[] args) {JavaCourseFactory factory = new JavaCourseFactory();factory.createNote().edit();factory.createVideo().record();}
}/*** 抽象工廠CourseFactory類:* 抽象工廠是用戶的主入口* 在Spring中應用得最為廣泛的一種設計模式* 易于擴展*/
public abstract class CourseFactory {public void init(){System.out.println("初始化基礎數據");}protected abstract INote createNote();protected abstract IVideo createVideo();
}/*** 創建Java產品族的具體工廠JavaCourseFactory*/
public class JavaCourseFactory extends CourseFactory {public INote createNote() {super.init();return new JavaNote();}public IVideo createVideo() {super.init();return new JavaVideo();}
}/*** 創建Java產品族,Java視頻JavaVideo類:Java視頻*/
public class JavaVideo implements IVideo {public void record() {System.out.println("錄制Java視頻");}
}/*** 錄播視頻:IVideo接口*/
public interface IVideo {void record();
}/*** 擴展產品等級Java課堂筆記JavaNote類:Java筆記*/
public class JavaNote implements INote {public void edit() {System.out.println("編寫Java筆記");}
}/*** 課堂筆記:INote接口*/
public interface INote {void edit();
}// 創建Python產品族的具體工廠PythonCourseFactory省略。。。上面的代碼完整地描述了兩個產品族Java課程和Python課程,也描述了兩個產品等級視頻和手記。抽象工廠非常完美清晰地描述這樣一層復雜的關系。但是,不知道大家有沒有發現,如果我們再繼續擴展 產品等級,將源碼 Source也加入到課程中,那么我們的代碼從抽象工廠,到具體工廠要全部調整,很顯然不符合開閉原則。
3.4.3.源碼
AbstractFactory
AnnotationApplicationContext
Xml
適合長時間不變動的場景
3.4.3.優缺點
抽象工廠缺點
- 規定了所有可能被創建的產品集合,產品族中擴展新的產品困難,需要修改抽象工廠的接口。
- 增加了系統的抽象性和理解難度。
3.5.簡單工廠 vs 工廠方法 vs 抽象工廠
簡單工廠:產品的工廠
工廠方法:工廠的工廠
抽象工廠:復雜產品的工廠
簡單工廠:工廠是一個實體類,內部直接根據邏輯創建對應的產品。
工廠方法:工廠首先有個接口定義規范。不同的產品使用不同的實體類工廠根據規范和需求創建對應的產品。這就是它們的區別。
工廠方法是生產一類產品,抽象工廠是生產一個產品族
3.6.作業
1、工廠類一定需要將構造方法私有化嗎,為什么?
不一定。抽象工廠類就不能,否則父類的私有構造方法就不能被子類調用。
2、用工廠模式設計支付業務場景,包含跨境支付,支付寶、微信、銀聯支付,并畫出類圖。
/*** description: 支付接口*/
public interface IPay {/*** 支付方法*/void pay();
}/*** description: 支付寶支付*/
public class AliPay implements IPay {public void pay() {System.out.println("支付寶支付");}
}/*** description: 微信支付*/
public class WxPay implements IPay {public void pay() {System.out.println("微信支付");}
}/*** description: 銀聯支付*/
public class UniPay implements IPay {public void pay() {System.out.println("銀聯支付");}
}/*** description: 蘋果支付*/
public class ApplePay implements IPay {public void pay() {System.out.println("蘋果支付");}
}/*** description: 支付抽象工廠*/
public abstract class AbstractPayFactory {public void init() {System.out.println("初始化基礎數據");}
}/*** description: 國內支付*/
public class ChinaPayFactory extends AbstractPayFactory {protected IPay createAliPay() {super.init();return new AliPay();}protected IPay createWxPay() {super.init();return new WxPay();}protected IPay createUniPay() {super.init();return new UniPay();}
}/*** description: 國外支付*/
public class ForeignPayFactory extends AbstractPayFactory {protected IPay createApplePay() {super.init();return new ApplePay();}
}/*** description: 抽象工廠方法測試*/
public class AbstractPayFactoryTest {public static void main(String[] args) {ChinaPayFactory chinaPayFactory = new ChinaPayFactory();chinaPayFactory.createAliPay().pay();chinaPayFactory.createWxPay().pay();chinaPayFactory.createUniPay().pay();ForeignPayFactory foreignPayFactory = new ForeignPayFactory();foreignPayFactory.createApplePay().pay();}
}
總結
以上是生活随笔為你收集整理的getinstance方法详解_二、设计模式总览及工厂模式详解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 冰天雪地
- 下一篇: pg 主键系统信息_神仙打架:PG 和