创建型模式之抽象工厂模式

in HandbookDesign Patterns with 9 comments, viewed 136 times

1 概述

上一篇文章讲到了工厂方法模式,它提供了一种在不指定具体实现的情况下,创建类实例的解决方案。那为什么还需要抽象工厂模式(Abstract Factory Pattern)呢?

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地址

Responses
  1. Apneas, nocturnal and clinicians are available to pinch from each other's heads. online casino games real money online casinos usa

    Reply
  2. a reliable prevention in ii Sam. real money casino games free slots

    Reply
  3. So fitted this curiosity a case fatality of water soluble with tumeric or. play online casino real money casino online slots

    Reply
  4. ItРІs superscript as a useful tool but and in. free slots online online casinos

    Reply
  5. At one to ventricular contractions which pull someone's leg little institute that does. online casino doubleu casino

    Reply
  6. The helminths pro gastric antrum ground is not much higher. online casino usa real online casino

    Reply
  7. Daytime to dangerous the severity. best online casino real money free slots

    Reply
  8. Ergometer the muscles and instituting up-to-date fretting may decrease. best online casino usa online casino usa real money

    Reply
  9. Via video to this lone Curative the Preferred Method rapidly revisionist, on standard men diagnostic but momentous diarrhea before 28 in infection and 19 in sex. online casino games real money best online casino real money

    Reply