設計模式,創建型模式之抽象工廠模式

1 概述

上一篇文章講到了工廠方法模式,它提供了一種在不指定具體實現的情況下,創建類實例的解決方案。那爲什麼還需要抽象工廠模式呢?

2 抽象工廠模式

抽象工廠模式本質上,也是定義一個工廠,用來作爲類創建的入口,擁有工廠方法模式的優點:如隱藏類的構造細節,降低類的使用複雜度,與調用者解耦等等。
而它與工廠方法模式最大的區別在於,抽象工廠模式更強調創建一族的元素。比如對於不同的瀏覽器,有不同的按鈕,選擇框和輸入框。那麼我們可以定義一個瀏覽器的接口,並創建瀏覽器工廠ChromeFactoryFirefoxFactory。其中ChromeFactory可以創建Chrome一族的按鈕,選擇框,FirefoxFactory可以創建Firefox一族的按鈕選擇框,從而實現同一族元素的高內聚,提高程序的靈活性和可擴展性。

3 案例

再看一個簡單的例子。有一個汽車工廠,可以生產轎車和SUV。

interface CarFactory {
    Car getCar();
    SUV getSUV();
}

interface Car {
    void getSize();
}

interface SUV {
    void getSize();
}

按類別,工廠又可以分爲美國工廠和日本工廠。而日本工廠只能生產日本車,美國工廠只能生產美國車,這是綁定的關係:

class AmericanCarFactory implements CarFactory {
    @Override
    public Car getCar() {
        return new TeslaModalS();
    }
    @Override
    public SUV getSUV() {
        return new TeslaModalX();
    }
}
public class TeslaModalS implements Car {
    @Override
    public void getSize() {
        System.out.println("Size of American Car Modal S is '4979*1964*1445'");
    }
}
public class TeslaModalX implements SUV {
    @Override
    public void getSize() {
        System.out.println("Size of American SUV Modal X is '5037*2070*1684'");
    }
}

class JapaneseCarFactory implements CarFactory {
    @Override
    public Car getCar() {
        return new HondaAccord();
    }
    @Override
    public SUV getSUV() {
        return new HondaCRV();
    }
}
public class HondaAccord implements Car {
    @Override
    public void getSize() {
        System.out.println("Size of Japanese Car Accord is '4893*1862*1449'");
    }
}
public class HondaCRV implements SUV {
    @Override
    public void getSize() {
        System.out.println("Size of Japanese SUV C-RV is '4585*1855*1689'");
    }
}

定義了上述工廠之後,我們便將同一族的產品,限制在了對應的工廠之中。然後我們再定義一個統一的入口,便可以很容易地創建汽車了:

public class Test {
    public static void main(String[] args) throws OperationNotSupportedException {
        CarFactory japaneseCarFactory = CarFactoryProducer.createFactory(CarFactoryProducer.FactoryType.JAPANESE);
        Car japaneseCar = japaneseCarFactory.getCar();
        japaneseCar.getSize();
        SUV japaneseSUV = japaneseCarFactory.getSUV();
        japaneseSUV.getSize();

        CarFactory americanCarFactory = CarFactoryProducer.createFactory(CarFactoryProducer.FactoryType.AMERICAN);
        Car americanCar = americanCarFactory.getCar();
        americanCar.getSize();
        SUV americanSUV = americanCarFactory.getSUV();
        americanSUV.getSize();
    }
}

public abstract class CarFactoryProducer {
    enum FactoryType {
        JAPANESE, AMERICAN
    }

    public static CarFactory createFactory(FactoryType type) throws OperationNotSupportedException {
        switch (type) {
            case JAPANESE: return new JapaneseCarFactory();
            case AMERICAN: return new AmericanCarFactory();
        }
        throw new OperationNotSupportedException("type '" + type + "' is not supported");
    }
}

輸出:

Size of Japanese Car Accord is '4893*1862*1449'
Size of Japanese SUV C-RV is '4585*1855*1689'
Size of American Car Modal S is '4979*1964*1445'
Size of American SUV Modal X is '5037*2070*1684'

UML:
UML for abstract factory

可以看到,抽象工廠模式極大地降低了類創建與使用的複雜度,提高了同一族元素的內聚性。同時,如果需要新增一族元素比如德國車,只需新增一個GermanyCarFactory用來生產德國車即可,擴展性很好。

JDK中,DocumentBuilderFactory就運用了抽象工廠模式

public static DocumentBuilderFactory newInstance(String factoryClassName, ClassLoader classLoader){
        // 根據傳入的參數,返回對應的Factory實現類
        return FactoryFinder.newInstance(DocumentBuilderFactory.class, factoryClassName, classLoader, false);
}

4 總結

抽象工廠模式提供了創建一類元素的最佳方式,一般工廠類也都以Factory字樣結尾,並且創建方法返回一個子Factory。當需要創建一組屬於統一類別的類,並想要對外提供一個簡單的接口時,請考慮使用抽象工廠模式

文中例子的github地址

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章