前面我们了解到工厂方法模式通过引入抽象工厂的概念,使得产品对象的创建可以依赖于具体工厂,但是这种设计模式最大的问题是会造成类的数量爆炸式增长。对于这个问题,抽象工厂模式通过引入两个新的概念:产品等级与产品簇,来解决工厂方法的工厂类过多的问题。
在正式进入抽象工厂模式学习之前,我们先来了解一下这两个概念:
- 产品等级(分类): 产品等级可以理解为一类相同的产品,可以理解为抽象产品下的子类实现。具体表现为,比如电视机是一类产品,可以有海尔电视机、小米电视机、TCL电视机等,这个电视系列就可以理解为一个产品等级。
- 产品簇: 产品簇可以理解为一组不同等级产品的组合,但是这些产品都是一个工厂的产品。具体表现为,比如海尔工厂生产电视机、电冰箱、洗衣机等,这些海尔生产的电器产品组合在一起形成一个产品簇。
1. 概述
抽象工厂模式:为创建一组对象提供了一种解决方案,与工厂方法模式相比,抽象工厂模式中的工厂角色不只创建一种产品,而是负责一个产品簇对象的生产。抽象工厂模式是一种创建型的设计模式。
在抽象工厂模式中,包含4个角色:
- 抽象工厂角色: 它声明了一组用于创建一个产品簇的方法,每个方法对应一种产品,它可以是接口或者抽象类。
- 具体工厂角色: 它实现了在抽象工厂中声明的创建具体产品的方法,生成一组具体的产品,这些产品组成一个产品簇,每种产品都属于一个产品等级。
- 抽象产品角色: 它是每种产品的抽象,可以是接口或者抽象类,声明产品的业务方法。
- 具体产品角色: 它继承抽象产品,实现了抽象产品中声明的业务方法,多个具体产品可以组成一个产品簇。
2. 代码实现
抽象工厂模式是一类比较复杂的对象创建型模式,复杂的地方在于产品簇和产品等级维度的划分,有时候业务界限比较模糊,这些都高度依赖于开发人员的业务素养和代码积累等。
接下来我们就以刚才海尔、美的工厂生产冰箱和电视机的产品为例子,写一个demo:
- 抽象的工厂接口
public interface AbstractFactory {
// 创建电视的方法
TelevisionProduct createTelevisionProduct();
// 创建冰箱的方法
RefrigeratorProduct createRefrigeratorProduct();
}
- 具体的实现类
/**
* 美的生产工厂
*/
class MideaFactory implements AbstractFactory {
// 实现创建电视的方法
@Override
public TelevisionProduct createTelevisionProduct() {
return new MideaTelevisionProduct();
}
// 创建冰箱的方法
@Override
public RefrigeratorProduct createRefrigeratorProduct() {
return new MideaRefrigeratorProduct();
}
}
/**
* 海尔生产工厂
*/
class HairFactory implements AbstractFactory {
// 实现创建电视的方法
@Override
public TelevisionProduct createTelevisionProduct() {
return new HairTelevisionProduct();
}
// 创建冰箱的方法
@Override
public RefrigeratorProduct createRefrigeratorProduct() {
return new HairRefrigeratorProduct();
}
}
- 抽象的产品角色
// 产品簇-冰箱产品
public interface RefrigeratorProduct {
void displayColor();
}
// 产品簇-电视机产品
public interface TelevisionProduct {
void displayShape();
}
- 具体的产品角色
// 海尔冰箱
public class HairRefrigeratorProduct implements RefrigeratorProduct {
@Override
public void displayColor() {
System.out.println("海尔冰箱");
}
}
// 海尔电视机
public class HairTelevisionProduct implements TelevisionProduct{
@Override
public void displayShape() {
System.out.println("海尔电视机");
}
}
// 美的冰箱
public class MideaRefrigeratorProduct implements RefrigeratorProduct {
@Override
public void displayColor() {
System.out.println("美的冰箱");
}
}
// 美的电视机
public class MideaTelevisionProduct implements TelevisionProduct{
@Override
public void displayShape() {
System.out.println("美的电视机");
}
}
- 客户端及运行结果
class Client {
public static void main(String[] args) {
// 美的工厂的产品簇
AbstractFactory mideaFactory = new MideaFactory();
RefrigeratorProduct mideaRefrigerator = mideaFactory.createRefrigeratorProduct();
mideaRefrigerator.displayColor();
TelevisionProduct mideaTelevision = mideaFactory.createTelevisionProduct();
mideaTelevision.displayShape();
System.out.println("========分割线========");
// 海尔工厂的产品簇
HairFactory hairFactory = new HairFactory();
RefrigeratorProduct hairRefrigerator = hairFactory.createRefrigeratorProduct();
hairRefrigerator.displayColor();
TelevisionProduct hairTelevision = hairFactory.createTelevisionProduct();
hairTelevision.displayShape();
}
}
美的冰箱
美的电视机
========分割线========
海尔冰箱
海尔电视机
3. UML类图
基于上面的这个抽象工厂的Demo,我们来画一下抽象工厂模式的UML类图。
4. 总结
抽象工厂模式是工厂方法模式的进一步延伸,在一些框架和API的类库设计中都得到了广泛的使用。下面,我们来总结一下这种设计模式的优缺点
4.1 优点
- 对象的创建和使用过程分离,用户无需关注对象的创建,只需要会使用工厂模式即可;
- 抽象工厂模式使得同一个产品簇的对象可以同时被创建,可以使得用户能同时使用这一个产品簇的对象;
- 产品簇维度的扩展很方便,直接增加实现即可,符合开闭原则。
4.2 缺点
抽象工作的缺点也很明显,像扩展产品分类是比较麻烦的,涉及到多个接口和类的关联修改,违背了开闭原则。