工廠模式(Factory Pattern)是 Java 中最經常使用的設計模式之一。這種類型的設計模式屬於建立型模式,它提供了一種建立對象的最佳方式。程序員
在工廠模式中,咱們在建立對象時不會對客戶端暴露建立邏輯,而且是經過使用一個共同的接口來指向新建立的對象。設計模式
工廠模式分爲三種:簡單工廠模式,工廠方法模式,抽象工廠模式。ide
簡單工廠模式是由一個工廠對象決定建立出哪種產品類的實例,是工廠模式家族中最簡單實用的模式。ui
簡單工廠模式,定義了一個建立對象的類,由這個類來封裝實例化對象的行爲。設計
在軟件開發中,當咱們要用到大量的建立某種,某類或者某批對象時,就會使用到工廠模式。code
假設咱們須要製做Pizza,咱們能夠用一個工廠類,根據類型返回對應的Pizza實例。orm
package factory.simple; public class SimpleFactoryTest{ public static void main(String[] args) { SimpleFactory sf = new SimpleFactory(); Pizza creamPizza = sf.createPizza("cream"); } } class SimpleFactory { public Pizza createPizza(String type) { switch(type){ case "cream": return new CreamPizza(); case "fruit": return new FruitPizza(); default: return null; } } } abstract class Pizza { } class CreamPizza extends Pizza { } class FruitPizza extends Pizza { }
簡單工廠模式也叫靜態工廠模式。即上面代碼中,能夠將createPizza方法改成靜態方法,調用方也不用實例化工廠對象了。對象
工廠方法模式:定義一個有實例化抽象方法的抽象工廠類,由工廠子類決定具體要實例化的類。工廠方法模式將對象的實例化推遲到子類。繼承
在上面的例子中,若是又有了新種類的Pizza,就須要修改createPizza方法。隨着Pizza種類不斷增長,建立披薩方法會不斷修改,這裏其實就違背了開閉原則(對擴展開發,對修改關閉),並且現實中也不可能一個工廠生產全部種類的披薩。接口
下面用工廠方法模式改進一下以前的代碼
package factory.method; public class FactoryMethodTest { public static void main(String[] args) { Factory f = new FruitFactory(); Pizza fruitPizza = f.createPizza(); } } abstract class Factory { abstract Pizza createPizza(); } class CreamFactory extends Factory { @Override Pizza createPizza() { return new CreamPizza(); } } class FruitFactory extends Factory { @Override Pizza createPizza() { return new FruitPizza(); } } abstract class Pizza { } class CreamPizza extends Pizza { } class FruitPizza extends Pizza { }
抽象工廠模式:定義了一個interface用於建立相關或有依賴關係的對象簇,而無需指明具體的類。
抽象工廠模式能夠將簡單工廠模式和工廠方法模式進行整合。
從設計層面看,抽象工廠就是對簡單工廠模式的改進(或者稱爲進一步的抽象)。
將工廠抽象爲兩層,抽象工廠和具體工廠子類。程序員根據要建立的對象類型使用對應的工廠子類,將單個的簡單工廠變成了工廠簇,更利於代碼的維護和擴展。
在上面例子中,假設工廠不僅生產披薩,還生產沙拉等系列產品。那麼代碼改進以下
package factory.abstract2; public class AbstractFactoryTest { public static void main(String[] args) { Factory f = new CreamFactory(); Pizza creamPizza = f.createPizza(); Salad creamSalad = f.createSalad(); } } abstract class Factory { abstract Pizza createPizza(); abstract Salad createSalad(); } class CreamFactory extends Factory { @Override Pizza createPizza() { return new CreamPizza(); } @Override Salad createSalad() { return new CreamSalad(); } } class FruitFactory extends Factory { @Override Pizza createPizza() { return new FruitPizza(); } @Override Salad createSalad() { return new FruitSalad(); } } abstract class Pizza { } class CreamPizza extends Pizza { } class FruitPizza extends Pizza { } abstract class Salad { } class CreamSalad extends Salad { } class FruitSalad extends Salad { }
在Calendar類中,實例化一個對象時,默認調用類的getInstance方法
public static Calendar getInstance() { return createCalendar(TimeZone.getDefault(), Locale.getDefault(Locale.Category.FORMAT)); }
繼續跟蹤createCalendar方法,能夠看到裏面用到了工廠模式(根據TimeZone和Locale建立對應的實例)
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; }
工廠模式的意義:將實例化對象的代碼提取出來,放到一個類中統一管理和維護,達到和主項目依賴關係解耦的目的。從而提升項目的可擴展性和維護性。
三種工廠模式:簡單工廠模式,工廠方法模式,抽象工廠模式
設計模式的依賴抽象原則