工廠模式

介紹

工廠模式(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 {
    
}

JDK實例

在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;
    }

小結

工廠模式的意義:將實例化對象的代碼提取出來,放到一個類中統一管理和維護,達到和主項目依賴關係解耦的目的。從而提升項目的可擴展性和維護性。

三種工廠模式:簡單工廠模式,工廠方法模式,抽象工廠模式

設計模式的依賴抽象原則

  1. 建立對象實例時,不要直接new類,而是把這個new類的動做放在一個工廠的方法中,並返回。有的書上說,變量不要直接持有具體類的引用
  2. 不要讓類繼承具體類,而是繼承抽象類或者實現接口
  3. 不要覆蓋基類中已經實現的方法
相關文章
相關標籤/搜索