本文從是什麼、爲何、怎麼作的三個步驟,分析簡單工廠模式、工廠方法模式和抽象工廠模式,經過框架源碼學習如何優雅地使用工廠模式。java
關於什麼是工廠模式這個問題呢?其實徹底能夠見名知意,工廠是作什麼的?工廠是生產產品的地方啊,那麼映射到編程領域,工廠模式不就是生產對象的一種模式嘛?借用百度百科的一句話來講:工廠模式是咱們最經常使用的實例化對象模式了,是用工廠方法代替new操做的一種模式。編程
工廠模式,按照業務實際場景能夠劃分爲3中不一樣的實現方式,分別是簡單工廠模式、工廠方法模式和抽象方法模式。設計模式
簡單工廠模式又叫靜態工廠方法模式,簡單來講就是,該模式有一個具體的工廠類,能夠生產許多不一樣的產品。有一件有意思的事情,簡單工廠模式其實不是一種設計模式(不屬於GoF23種設計模式),更像是一種編程等習慣,可是因爲該習慣常常被使用,許多開發人員都把它稱爲」工廠模式「,那麼就」將錯就錯「被你們所接受咯。框架
在簡單工廠模式中,生產產品是由一個單一的、具體的工廠類來實現的;在工廠方法模式中,再也不採用這種方式,而是由工廠類的子類實現具體產品的生產工做。當增長一類產品的時候,只須要增長一個相應的工廠類的子類。這樣作的好處是能夠解決簡單工廠模式因爲生產產品種類過多而引起的代碼臃腫的問題。舉個例子,須要建立3種類型的產品,簡單工廠模式須要3個分支(無論是if-else也好,switch-case也罷),工廠方法模式須要3個子類;那麼產品類型有10種呢?當生產的產品種類較多的時候,使用工廠方法模式能夠解決簡單工廠方法模式大量代碼重複的問題,這也就是工廠方法模式存在的意義。ide
抽象工廠模式是這麼定義的:抽象工廠模式提供一個接口,用於建立相關或依賴對象的家族,而不須要明確執行具體類。抽象工廠容許客戶使用抽象的接口來建立一組相關的產品,而不須要關係實際產出的具體產品是什麼。學習
」爲何要使用工廠模式「,關於這個問題我是這麼理解的:設計
第一,爲何要使用設計模式?逼格,對,設計模式就是逼格的體現。除了逼格,說的實際點,就是可使代碼變得清晰和優雅,讓新人接手代碼的時候在內心少罵咱們幾句。code
第二,主要的目的仍是解耦。若是沒有簡單工廠模式,咱們須要關心生產邏輯(建立過程)和調用,可使用一坨代碼去實現,此時這兩者是沒有分開的;當使用了簡單工廠模式,具體的生產邏輯放在了簡單工廠裏面,只須要調用便可;當品類增多,簡單工廠的工廠類的邏輯變得複雜,耦合變得嚴重,出現工廠方法模式,將不一樣品類的生產邏輯剝離到子類中進行,讓外部只是知道如何調用便可,實現解耦....其實從不使用設計模式--> 簡單工廠模式--> 工廠方法模式-->抽象工廠模式,這就是層次遞進的解耦關係。那爲何須要使用工廠模式呢,我想本質也就在這裏吧。orm
關於如何使用工廠模式?不寫以前的demo了,來看下優秀的框架中是如何使用工廠模式的。對象
簡單工廠模式java.util.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源碼中的工廠方法模式的使用:
public static Logger getLogger(String name){ ILoggerFactory iLoggerFactory = getILoggerFactory(); return iLoggerFactory.getLogger(name); } public static Logger getLogger(Class clazz){ return getLogger(clazz.getName()); }
在Spring源碼中,全部工廠都是BeanFactory的子類。經過對BeanFactory的實現,咱們能夠從Spring的容器訪問Bean。根據不一樣的策略調用getBean()方法,從而得到具體對象。
public interface BeanFactory { String FACTORY_BEAN_PREFIX = "&"; Object getBean(String var1) throws BeansException; <T> T getBean(String var1, Class<T> var2) throws BeansException; Object getBean(String var1, Object... var2) throws BeansException; <T> T getBean(Class<T> var1) throws BeansException; <T> T getBean(Class<T> var1, Object... var2) throws BeansException; <T> ObjectProvider<T> getBeanProvider(Class<T> var1); <T> ObjectProvider<T> getBeanProvider(ResolvableType var1); boolean containsBean(String var1); boolean isSingleton(String var1) throws NoSuchBeanDefinitionException; boolean isPrototype(String var1) throws NoSuchBeanDefinitionException; boolean isTypeMatch(String var1, ResolvableType var2) throws NoSuchBeanDefinitionException; boolean isTypeMatch(String var1, Class<?> var2) throws NoSuchBeanDefinitionException; @Nullable Class<?> getType(String var1) throws NoSuchBeanDefinitionException; @Nullable Class<?> getType(String var1, boolean var2) throws NoSuchBeanDefinitionException; String[] getAliases(String var1); }