一、简介
抽象工厂模式(Abstract Factory Pattern)也是一种创建型设计模式,它提供了一种创建一系列相关或者相依赖对象的工厂接口(超级工厂),不同类型的工厂再去实现这个抽象工厂,最后还可提供一个工厂创造者类,通过传入工厂类型参数来创建具体工厂。它是对工厂方法模式的扩展,核心思想是将工厂本身也抽象化,其主旨是围绕一个超级工厂或中心工厂去创建其他工厂,这个超级工厂又称为其他工厂的工厂。
它与工厂方法模式的区别就在于,工厂方法模式针对的是一个产品等级;而抽象工厂模式则是针对的多个产品等级,即一个产品族。在编程中,通常一个产品等级,表现为一个接口或者抽象类及其下的实现类,也就是说,工厂方法模式提供的所有产品都是衍生自同一个接口或抽象类,而抽象工厂模式所提供的产品则是衍生自不同的接口或抽象类。
所谓的产品族,是指位于不同产品等级中功能相关联的产品组成的家族。抽象工厂模式所提供的一系列产品就组成一个产品族;而工厂方法提供的一系列产品组成一个产品等级。
对比现实生活,一个产品族,如数码产品。一个产品等级,如手机,包括所有品牌的手机都属于这个产品等级,而所有笔记本电脑又是另一个产品等级。所有手机和电脑共同构成数码产品这个产品族。
设计原理
抽象工厂模式通常包含四个必要角色和一个可选角色:
- 抽象工厂(Abstract Factory):定义一个接口或抽象类,它声明了一组用于创建相关产品对象的方法,这些方法的返回值通常是一个抽象产品。
- 具体工厂(Concrete Factory):它实现了抽象工厂中声明的创建产品对象的方法,同一产品等级下根据不同的产品参数,创建一个具体产品对象。
- 抽象产品(Abstract Product):定义一个接口或抽象类,表示同类产品,在抽象产品中声明了产品所具有的方法。
- 具体产品(Concrete Product):它定义了抽象产品下所拥有的具体产品,实现了抽象产品接口中定义的业务方法。
- 工厂创造器(可选角色):提供一个静态方法,根据传入不同的工厂类型参数,创造一个具体的工厂类,返回值用抽象工厂接收。
UML类图
扩展性分析
Tip:很多文章中写的是扩展一个产品族,我不是很理解这种说法,抽象工厂模式整个对应的就只有一个产品族。我觉得应该是汉语理解的问题,只能说扩展产品族,而不能说扩展一个产品族,前者表示我要在一个产品族下新增一个产品等级,后者表示我要新增一个全新的产品族,这就不是扩展了,而是另起炉灶。我是这样理解的,欢迎大家来质疑。
扩展一个产品
需要扩展一个具体产品。同时修改具体工厂层的部分代码。小程度地违背开闭原则。
扩展一个产品等级
需要同时扩展抽象产品层和具体产品层。还要修改最顶层的抽象工厂层来添加额外的创建方法,这会导致所有具体工厂实现都要同步修改,这是非常麻烦的,极大地违背了开闭原则。
优点
- 将产品的创建和使用分离开来,使得客户端代码更加简洁,并且向客户端隐藏产品的创建细节。
- 将一系列相关的产品对象的创建工作统一到一个抽象工厂中,客户端只需要访问抽象工厂即可,具体的产品工厂可以灵活替换。
- 当一个族中的多个对象被设计成一起工作时, 它能够保证客户端始终只使用同一个族中的对象。
缺点
- 一个产品族下增加新的产品等级非常困难,甚至需要修改抽象层代码和其下所有的实现, 严重违背了“开闭原则”。
- 增加了代码的复杂性,增加了系统的抽象性,增加了理解难度。
适用场景
- 系统需要一系列相关或相互依赖的产品对象,并且这些产品对象的实现可能会随着时间的推移而发生变化。
- 系统需要在运行时动态地选择产品族中的一种,而不是一种单一的产品。
- 系统需要保证一组产品对象被设计成一起使用,而不是单独使用。
- 系统需要对一个产品族下不同产品提供统一的访问接口,而不关心产品的具体实现。
二、实现案例
模拟一个产品族,这个产品族包括”形状“和”颜色“两个产品等级,提供相应的创建方法。
1. 代表“形状”的抽象产品层和具体产品层
Tip:注意这里是一个接口,两个实现类,共同定义在一个Shape.java的文件中了。下同。
public interface Shape {
void draw();
}
class Square implements Shape{
@Override
public void draw() {
System.out.println("我是正方形");
}
}
class Circle implements Shape{
@Override
public void draw() {
System.out.println("我是圆形");
}
}
2. 代表“颜色”的抽象产品层和具体产品层
public interface Color {
void fill();
}
class Red implements Color{
@Override
public void fill() {
System.out.println("我是红色");
}
}
class Blue implements Color{
@Override
public void fill() {
System.out.println("我是蓝色");
}
}
3. 抽象工厂和具体工厂层
//抽象工厂类
public interface AbstractFactory {
Shape getShape(String shape);
Color getColor(String color);
}
//形状工厂类
class ShapeFactory implements AbstractFactory {
@Override
public Shape getShape(String shape){
if("square".equalsIgnoreCase(shape)){
return new Square();
} else if("circle".equalsIgnoreCase(shape)){
return new Circle();
}else{
return null;
}
}
@Override
public Color getColor(String color) {
return null;
}
}
//颜色工厂类
class ColorFactory implements AbstractFactory {
@Override
public Shape getShape(String shape){
return null;
}
@Override
public Color getColor(String color) {
if("red".equalsIgnoreCase(color)){
return new Red();
} else if("blue".equalsIgnoreCase(color)){
return new Blue();
}else{
return null;
}
}
}
5. 工厂创造器
public class FactoryProducer {
//工厂创造器
public static AbstractFactory createFactory(String choice){
if("shape".equalsIgnoreCase(choice)){
return new ShapeFactory();
} else if("color".equalsIgnoreCase(choice)){
return new ColorFactory();
}else{
return null;
}
}
}
6. 测试类
public class Test {
public static void main(String[] args) {
//测试形状工厂
AbstractFactory absFactory01=FactoryProducer.createFactory("shape");
absFactory01.getShape("circle").draw();
//测试颜色工厂
AbstractFactory absFactory02=FactoryProducer.createFactory("color");
absFactory02.getColor("red").fill();
//不使用工厂创造器,直接new的形式
AbstractFactory absFactory03=new ColorFactory();
absFactory03.getColor("blue").fill();
}
}
运行结果示例:
三、总结
好了,亲爱的读者朋友们,辛苦大家看到这里,经过本篇博客文章的学习,相信大家已经对抽象工厂模式有了非常深刻的认知。对比工厂方法模式,这个模式确实更加复杂和难以掌握,本文尽量以通俗易懂的形式阐述了抽象工厂模式的设计原理、扩展性及优缺点分析,希望大家结合案例认真理解它的用法,如有疑问欢迎评论斧正。
创作不易,如果本文对你有帮助,欢迎点赞、收藏加关注,你的支持和鼓励,是我创作的最大动力。