第三章 抽象工厂模式
在工厂方法模式中,通过引入工厂等级结构,解决了 简单工厂模式 中工厂类过于庞大,职责过重的问题。但是由于工厂方法模式中的每一个工厂只生产一类产品,导致系统中存在大量工厂类,增加系统开销。
因此我们需要将一些相关的产品组成一个“产品族”,由同一个工厂生产。
一、抽象工厂模式
1.1 设计一款界面皮肤库
设计一款界面皮肤库,可以通过菜单来选择皮肤,不同的皮肤将提供视觉效果不同的按钮、文本框、组合框等。
按照之前的 工厂方法模式
设计,如下:
当我们需要增加 Winter风格 的按钮时,只需要继承抽象工厂并生产出对应的按钮即可。该系统具备良好的灵活性和可扩展性,开发可以在不修改现有代码的基础上增加新的皮肤。
1.2 缺陷与问题
该设计模式提供了大量的工厂来创建具体的界面组件,可以灵活的配置风格,但是存在以下问题:
- 新增产品时,需要同时新增一个具体工厂类,类的个数成对增加,会增大系统的开销
- 由于某一种风格的按钮、文本框、组合框通常都是一起使用的,但是因为其工厂方法分离,可能会导致使用时的选择失误
1.3 解决方案
将一组产品类定义为一个“产品族”(如按钮、文本框、组合框统称为一个产品族),将之前一个产品对应一个具体工厂的模式改为-一个产品族对应一个产品工厂(如Spring风格工厂,能够生产Spring风格按钮、Spring风格文本框、Spring风格组合框)。
1.4 产品等级结构与产品族
- 产品等级结构
- 在
1.3 解决方案
中,抽象工厂与Spring风格工厂、Summer风格工厂之间的关系构成了一个产品等级结构 - 抽象工厂类是父类,具体工厂类是子类
- 产品等级扩展,只需要继续实现子类即可(如新增Winter风格工厂,用于生产Winter风格的按钮、文本框、组合框)
- 在
- 产品族:
- 即各个具体工厂生产的产品统称(如Spring风格工厂,能够生产Spring风格按钮、Spring风格文本框、Spring风格组合框)
当系统所提供的工厂生产的具体产品并不是一个简单的对象,而是位于多个不同产品等级结构、属于不同类型的具体产品时就可以使用抽象工厂模式。
二、抽象工厂模式
2.1 概述
抽象工厂模式:提供一个创建一系列相关或互相依赖对象的接口,而无须指定它们具体的类。
抽象工厂模式又称为 Kit模式,属于对象创建型模式。
在抽象工厂模式中,每一个具体工厂都提供多个工厂方法,用于生产多种不同类型的产品。这些产品构成了一个产品族。
从图中可以看出,如果需要新增其他风格的按钮、文本框,只需要新增一个具体工厂,由该工厂的多个工厂方法产出具体的产品。
同时,缺点也很明显,如果我们想新增图片类型产品,必须同时修改抽象工厂及其所有的具体工厂。
2.2 抽象工厂模式中的几个角色
- AbstractFactory - 抽象工厂
- 声明了一组用于创建一族产品的方法,每一个方法对应一种产品
- ConcreteFactory - 具体工厂
- 实现了在抽象工厂中声明的创建产品的方法,生成一组具体产品,这些产品构成一个产品族
- AbstractProduct - 抽象产品
- 每种产品的抽象对象
- ConcreteProduct 具体产品
- 由具体工厂生产的具体产品对象
2.3 具体实践
/**
* 手机游戏软件
* 针对 Symbian、Android、WindowsPhone 等多个智能手机平台,
* 提供不同的游戏操作控制和游戏界面控制
*/
public class Gaming {
// 抽象产品类
interface Operation{}
// 具体产品类
class SymbianOperation implements Operation{}
class AndroidOperation implements Operation{}
class WindowsPhoneOperation implements Operation{}
interface HML{}
class SymbianHML implements HML{}
class AndroidHML implements HML{}
class WindowsPhoneHML implements HML{}
// 抽象工厂类
interface Factory{
Operation getOperation();
HML getHML();
}
// 具体工厂类
class SymbianFactory implements Factory{
@Override
public Operation getOperation() {
return new SymbianOperation();
}
@Override
public HML getHML() {
return new SymbianHML();
}
}
class AndroidFactory implements Factory{
@Override
public Operation getOperation() {
return new AndroidOperation();
}
@Override
public HML getHML() {
return new AndroidHML();
}
}
class WindowsPhoneFactory implements Factory{
@Override
public Operation getOperation() {
return new WindowsPhoneOperation();
}
@Override
public HML getHML() {
return new WindowsPhoneHML();
}
}
}
三、“开闭原则”的倾斜性
在抽象工厂模式中,增加新的产品族很方便(如增加Winter类型的界面),但是增加新的产品等级结构很麻烦(如增加单选框类型的产品,需要修改抽象工厂及其所有的具体工厂),这种性质被称为“开闭原则”的倾斜性。
“开闭原则”要求系统对扩展开发,对修改封闭,通过扩展达到增强其功能的目的,对于设计多个产品族与多个产品等级结构的系统,其功能增强包括两方面:
- 增加产品族,很好地支持了“开闭原则”,只需新增具体产品和新增一个具体工厂即可
- 增加产品等级结构:违背了“开闭原则”,因为需要修改所有的抽象工厂与具体工厂才能实现扩展
四、总结
优点
- 抽象工厂模式隔离了具体类的生成,使客户不需要知道何时被创建
- 当一个产品族中的多个对象被设计为一起工作时,它能够保证客户端始终只使用一个产品族对象
- 增加新的产品族很方便,无须修改已有系统,符合“开闭原则”
缺点
- 增加新的产品等级结构时,违背了“开闭原则”
适用场景
- 系统不依赖于产品类的具体创建、组合及表达的细节
- 系统中有多于一个的产品族,且每次只使用其中某一个产品族
- 同一个产品族的产品配合使用
- 产品等级结构稳定,设计完成后,不再修改系统中新的产品等级结构