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](https://my.oschina.net/u/1162528)
public Car getCar() {
return new TeslaModalS();
}
[@Override](https://my.oschina.net/u/1162528)
public SUV getSUV() {
return new TeslaModalX();
}
}
public class TeslaModalS implements Car {
[@Override](https://my.oschina.net/u/1162528)
public void getSize() {
System.out.println("Size of American Car Modal S is '4979*1964*1445'");
}
}
public class TeslaModalX implements SUV {
[@Override](https://my.oschina.net/u/1162528)
public void getSize() {
System.out.println("Size of American SUV Modal X is '5037*2070*1684'");
}
}
class JapaneseCarFactory implements CarFactory {
[@Override](https://my.oschina.net/u/1162528)
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
。当需要创建一组属于统一类别的类,并想要对外提供一个简单的接口时,请考虑使用抽象工厂模式。
来源:oschina
链接:https://my.oschina.net/u/2411391/blog/3207725