概念
抽象工厂模式(Abstract Factory Pattern)是指提供一个创建一系列相关或相互依赖对象的接口,无须指定他们具体的类。客户端(应用层)不依赖于产品类实例如何被创建、实现等细节,强调的是一系列相关的产品对象(属于同一产品族)一起使用创建对象需要大量重复的代码。需要提供一个产品类的库,所有的产品以同样的接口出现,从而使客户端不依赖于具体实现。
角色
- AbstractFactory(抽象工厂):它声明了一组用于创建一族产品的方法,每一个方法对应一种产品。
- ConcreteFactory(具体工厂):它实现了在抽象工厂中声明的创建产品的方法,生成一组具体产品,这些产品构成了一个产品族,每一个产品都位于某个产品等级结构中。
- AbstractProduct(抽象产品):它为每种产品声明接口,在抽象产品中声明了产品所具有的业务方法。
- ConcreteProduct(具体产品):它定义具体工厂生产的具体产品对象,实现抽象产品接口中声明的业务方法。
结构图
案例
以课程为例,假设一个课程需要提供录播视频、笔记、源码等资源才构成完整的课程。
创建 IVideo 和 INote 接口:
public interface IVideo{
void record();
}
public interface INote{
void edit();
}
创建抽象工厂类 CourseFactory :
public abstract class CourseFactory{
public void init(){
System.out.println("初始化数据");
}
protected abstract IVideo createNote();
protected abstract INote createNote();
}
创建 Java 产品族,Java 视频 JavaVideo 类:
public class JavaVideo implements IVideo{
public void record(){
System.out.println("录制 Java 视频");
}
}
扩展产品等级 Java 课堂笔记 JavaNote 类:
public class JavaNote implements INote{
public void edit(){
System.out.println("编写 Java 笔记");
}
}
创建 Java 产品族的具体工厂:
public class JavaCourseFactory extends CourseFactory{
public INote createNote(){
super.init();
return new JavaNote();
}
public IVideo createVideo(){
super.init();
return new JavaVideo();
}
}
Python 产品同理:
public class PythonVideo implements IVideo{
public void record(){
System.out.println("录制 Python 视频");
}
}
public class PythonNote implements INote{
public void edit(){
System.out.println("编写 Python 笔记");
}
}
Python 产品族具体工厂:
public class PythonCourseFactory implements CourseFactory{
public IVideo createVideo(){
return new PythonVideo();
}
public INote createNote(){
return new PythonNote();
}
}
客户端调用代码:
public static void main(String[] args){
JavaCourseFactory factory = new JavaCourseFactory();
factory.createNote.edit();
factory.createVideo.record();
}
开闭原则的倾斜性
在抽象工厂模式中,增加新的产品族很方便,但是增加新的产品等级结构很麻烦,抽象工厂模式的这种性质称为“开闭原则”的倾斜性。“开闭原则”要求系统对扩展开放,对修改关闭,通过扩展达到增强其功能的目的,对于涉及到多个产品族与多个产品等级结构的系统,其功能增强包括两方面:
- 增加产品族:对于增加新的产品族,抽象工厂模式很好地支持了“开闭原则”,只需要增加具体产品并对应增加一个新的具体工厂,对已有代码无须做任何修改。
- 增加新的产品等级结构:对于增加新的产品等级结构,需要修改所有的工厂角色,包括抽象工厂类,在所有的工厂类中都需要增加生成新产品的方法,违背了“开闭原则”。
总结
优点
- 抽象工厂模式隔离了具体类的生成,使得客户并不需要知道什么被创建。由于这种隔离,更换一个具体工厂就变得相对容易,所有的具体工厂都实现了抽象工厂中定义的那些公共接口,因此只需改变具体工厂的实例,就可以在某种程度上改变整个软件系统的行为
- 当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象
- 增加新的产品族很方便,无须修改已有系统,符合开闭原则
缺点
- 增加新的产品等级结构麻烦,需要对原有系统进行较大的修改,甚至需要修改抽象层代码,违背了开闭原则
适用场景
- 一个系统不应当依赖于产品类实例如何被创建、组合和表达的细节,这对于所有类型的工厂模式都是很重要的,用户无须关心对象的创建过程,将对象的创建和使用解耦
- 系统中有多于一个的产品族,而每次只使用其中某一产品族。可以通过配置文件等方式来使得用户可以动态改变产品族,也可以很方便地增加新的产品族
- 属于同一个产品族的产品将在一起使用
- 产品等级结构稳定,设计完成之后,不会向系统中增加新的产品等级结构或者删除已有的产品等级结构