抽象工厂(Abstract Factory)
抽象工厂模式提供一个创建一系列相关或相互依赖对象的接口。
抽象工厂是面向产品族的,而工厂方法是面向产品等级结构的,这是两者的主要区别。
适用场景:
- 客户端不依赖于产品类实例如何被创建、实现等细节
- 强调一系列相关的产品对象(属于同一产品族)一起使用创建对象时需要大量重复的代码
- 提供一个产品类的库,所有的产品以同样的接口出现
优缺点
优点:具体产品在应用层代码隔离,无须关心创建细节;将一个系列的产品族统一到一起创建。
缺点:规定了所有可能被创建的产品集合,产品族中扩展新的产品困难,需要修改抽象工厂的接口。
应用场景
对于一个课程,既包含课程视频,也包含课程笔记:
抽象视频产品Video
:
public abstract class Video {
public abstract void produce();
}
具体视频产品JavaVideo
、PythonVideo
:
public class JavaVideo extends Video {
@Override
public void produce() {
System.out.println("录制Java课程视频");
}
}
public class PythonVideo extends Video{
@Override
public void produce() {
System.out.println("录制Python课程视频");
}
}
同样,也有抽象笔记产品Article
和具体笔记产品JavaArticle
、PythonArticle
:
public abstract class Artical {
public abstract void produce();
}
public class JavaArticle extends Artical {
@Override
public void produce() {
System.out.println("编写Java课程手记");
}
}
public class PythonArticle extends Artical{
@Override
public void produce() {
System.out.println("编写Python课程手记");
}
}
课程的抽象工厂CourseFactory
,生产视频和笔记两类产品:
public interface CourseFactory {
Video getVideo();
Artical getArtical();
}
Java课程的具体工厂JavaCourseFactory
:
public class JavaCourseFactory implements CourseFactory {
public Video getVideo() {
return new JavaVideo();
}
public Artical getArtical() {
return new JavaArticle();
}
}
Python课程的具体工厂PythonCourseFactory
:
public class PythonCourseFactory implements CourseFactory {
public Video getVideo() {
return new PythonVideo();
}
public Artical getArtical() {
return new PythonArticle();
}
}
客户端Test
:
public class Test {
public static void main(String[] args) {
CourseFactory courseFactory = new JavaCourseFactory();
Video video = courseFactory.getVideo();
Artical artical = courseFactory.getArtical();
video.produce();
artical.produce();
}
}
可以看出,每一个具体工厂中都只会生产同一产品族下的产品。如果要扩展新的产品族,例如要添加一个算法课程,则添加一个AlgorithmCourseFactory
工厂类即可,十分简单;但是如果要增加新的产品等级,比如在课程中除了视频和笔记外还要添加源码,那么就要修改抽象工厂中的实现,并且每一个具体工厂的实现也都要修改,抽象工厂模式在这种场景下就不适用了。
Connection中的应用
java.sql.Connection
接口定义了与指定数据库的连接:
public interface Connection extends Wrapper, AutoCloseable {
//...
Statement createStatement() throws SQLException;
PreparedStatement prepareStatement(String sql) throws SQLException;
//...
}
其中,Statement
、PreparedStatement
等也都为接口。我们查看Connection
的其中一个实现类ConnectionImpl
:
public class ConnectionImpl extends ConnectionPropertiesImpl implements Connection {
//...
public Statement createStatement() throws SQLException {
return this.createStatement(1003, 1007);
}
public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException {
this.checkClosed();
StatementImpl stmt = new StatementImpl(this, this.database);
stmt.setResultSetType(resultSetType);
stmt.setResultSetConcurrency(resultSetConcurrency);
return stmt;
}
//...
}
在createStatement
方法中实例化了Statement
接口的一个具体实现类,也就是com.mysql.jdbc.StatementImpl
。
由此可见,在这个场景中Connection
相当于一个抽象工厂,而ConnectionImpl
是一个具体工厂,抽象产品为Statement
,具体产品为StatementImpl
。在这个例子中,mysql产品族的工厂只会生产mysql的Statement、PreparedStatement等产品。
参考资料
- 弗里曼. Head First 设计模式 [M]. 中国电力出版社, 2007.
- 慕课网java设计模式精讲 Debug 方式+内存分析