1 概述
上一篇文章講到了工廠方法模式,它提供了一種在不指定具體實現的情況下,創建類實例的解決方案。那爲什麼還需要抽象工廠模式呢?
2 抽象工廠模式
抽象工廠模式本質上,也是定義一個工廠,用來作爲類創建的入口,擁有工廠方法模式的優點:如隱藏類的構造細節,降低類的使用複雜度,與調用者解耦等等。
而它與工廠方法模式最大的區別在於,抽象工廠模式更強調創建一族的元素。比如對於不同的瀏覽器,有不同的按鈕,選擇框和輸入框。那麼我們可以定義一個瀏覽器的接口,並創建瀏覽器工廠ChromeFactory
,FirefoxFactory
。其中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:
可以看到,抽象工廠模式極大地降低了類創建與使用的複雜度,提高了同一族元素的內聚性。同時,如果需要新增一族元素比如德國車,只需新增一個GermanyCarFactory
用來生產德國車即可,擴展性很好。
在JDK
中,DocumentBuilderFactory就運用了抽象工廠模式:
public static DocumentBuilderFactory newInstance(String factoryClassName, ClassLoader classLoader){
// 根據傳入的參數,返回對應的Factory實現類
return FactoryFinder.newInstance(DocumentBuilderFactory.class, factoryClassName, classLoader, false);
}
4 總結
抽象工廠模式提供了創建一類元素的最佳方式,一般工廠類也都以Factory
字樣結尾,並且創建方法返回一個子Factory
。當需要創建一組屬於統一類別的類,並想要對外提供一個簡單的接口時,請考慮使用抽象工廠模式。