抽象工厂模式/Abstract Factory
意图/适用场景:
抽象工厂模式适用于这样一种场景:
- 产品是成系列的,每一个系列的产品由多个不同的产品组成,这些产品有一些相似的特性,比如属于同一色系。
- 每一种产品又有很多种类,这些不同的产品可用一个产品继承树来表示。
- 系统中存在多个产品系列,但每次只需要产生一个系列出来工作,其它则不用。
- 总结以上的需求,产品类有这样的一种结构:
- 每一类产品有一个继承关系树,树上的子类是不同品种的产品。
- 所有产品类继承关系树的结构是完全一样的。
- 处在产品继承关系树相同位置的产品构成一个系列。
- 系统每次生产使用一个系列的产品。
抽象工厂模式以这样的方式来支持这个系统中产品的生产:
- 定义一个与产品类继承关系树同样结构的生产者树,树上的每一个具体生产者子类负责生产一个产品系列中的所有具体产品。
UML:
参与者:
- 抽象产品(AbstractProduct):为一类产品对象声明一个接口。
- 具体产品(ConcreteProduct):定义一个将被相应的具体工厂创建的产品对象。实现AbstractProduct接口。
- 抽象工厂(AbstractFactory):声明一个创建抽象产品对象的操作接口。
- 具体工厂(ConcreteFactory):实现创建具体产品对象的操作。
要点:
AbstractFactory模式有下面的一些优点和缺点:
- 它分离了具体的类
- AbstractFactory模式帮助你控制一个应用创建的对象的类。因为一个工厂封装创建产品对象的责任和过程,它将客户与类的实现分离。客户通过它们的抽象接口操纵实例。产品的类名也在具体工厂的实现中被分离;它们不出现在客户代码中。
- 它使得易于交换产品系列
- 一个具体工厂类在一个应用中仅出现一次—即在它初始化的时候。这使得改变一个应用的具体工厂变得很容易。它只需改变具体的工厂即可使用不同的产品配置,这是因为一个抽象工厂创建了一个完整的产品系列,所以整个产品系列会立刻改变。在我们的用户界面的例子中,我们仅需转换到相应的工厂对象并重新创建接口,就可实现从Motif窗口组件转换为PresentationManager窗口组件。
- 它有利于产品的一致性
- 当一个系列中的产品对象被设计成一起工作时,一个应用一次只能使用同一个系列中的对象,这一点很重要。而AbstractFactory很容易实现这一点。
- 难以扩展抽象工厂以生产新种类的产品
这是因为AbstractFactory接口确定了可以被创建的产品集合。支持新种类的产品就需要扩展该工厂接口,这将涉及AbstractFactory类及其所有子类的改变。我们会在实现一节讨论这个问题的一个解决办法。
应用实例:
试想一个支持多种外观风格的应用程序或者桌面套件。在它所支持的每一种外观风格中,Button和Scrollbar等组件都是不一样的,它们都是单独的产品。但是所有的Button都继承于一个公共的AbstractButton,而所有的Scrollbar也都处在一个继承树结构中;对某一个外观风格而言,它所选取的每一个组件都处在其产品树的同一位置上。
这时就可以定义一个工厂树,它的结构与每一个组件的树结构相同,一个工厂类就负责生产一种外观风格的所有组件产品。
示例代码:
[java]
// Source code from file:ConcreteCreatorA.java
packagedesignPatterns.AbstractFactory;
publicclass ConcreteCreatorA implements Creator {
publicProductI createProductI() {
returnnew ProductIA();
}
publicProductII createProductII() {
returnnew ProductIIA();
}
}
// Source code from file:ConcreteCreatorB.java
packagedesignPatterns.AbstractFactory;
publicclass ConcreteCreatorB implements Creator {
publicProductI createProductI() {
returnnew ProductIB();
}
publicProductII createProductII() {
returnnew ProductIIB();
}
}
// Source code from file:Creator.java
packagedesignPatterns.AbstractFactory;
publicinterface Creator {
publicProductI createProductI();
publicProductII createProductII();
}
// Source code from file:ProductI.java
packagedesignPatterns.AbstractFactory;
publicinterface ProductI {
}
// Source code from file:ProductIA.java
packagedesignPatterns.AbstractFactory;
publicclass ProductIA implements ProductI {
}
// Source code from file:ProductIB.java
packagedesignPatterns.AbstractFactory;
publicclass ProductIB implements ProductI {
}
// Source code from file:ProductII.java
packagedesignPatterns.AbstractFactory;
publicinterface ProductII {
}
// Source code from file:ProductIIA.java
packagedesignPatterns.AbstractFactory;
publicclass ProductIIA implements ProductII {
}
// Source code from file:ProductIIB.java
packagedesignPatterns.AbstractFactory;
publicclass ProductIIB implements ProductII {
}
// Source code from file:User.java
packagedesignPatterns.AbstractFactory;
publicclass User {
publicstatic void main(String[] args) {
Creator creator =null;
// now create product series A
creator =new ConcreteCreatorA();
creator.createProductI();
creator.createProductII();
// now create product series B
creator =new ConcreteCreatorB();
creator.createProductI();
creator.createProductII();
}
}
[/java]