设计模式四之抽象工厂模式
上面介绍的工厂方法模式中考虑的是一类产品的生产,畜牧场只产动物,洗衣机厂只产洗衣机,计算机软件学院只教计算机软件的学生等。
同种类称为同等级,也就是说,工厂方法模式只生产同等级的产品。但是在现实生活中很多工厂都是综合性的工厂,能生产多等级(种类)的产品,如农场里既养动物又种植物,电器厂既生产电视机又生产洗衣机或空调,大学既有软件专业又有生物专业等。
本节要介绍的抽象工厂模式将考虑多等级产品的生产,将同一个具体工厂所生产的位于不同等级的一组产品称为一个产品族,图 1 所示的是海尔工厂和 TCL 工厂所生产的电视机与空调对应的关系图。
1. 模式的定义与特点
1.1 模式的定义
抽象工厂(Abstract Factory)模式的定义:为访问类提供一个创建一系列相关或相互依赖的接口,且访问类无需指定所要产品的具体类就能得到同族的不同等级的产品。
抽象工厂模式是工厂方法模式的升级版本,工厂方法模式只生产一个等级的产品,而抽象工厂模式可生产多个等级的产品。
使用抽象工厂模式一般要满足以下条件:
- 系统中有多个产品族,每个具体工厂创建同一族但属于不同等级结构的产品。
- 系统一次只可能消费其中某一族产品,即同族的产品一起使用。
1.2 模式的优缺点
1. 抽象工厂模式的优点有:
- 将一系列的产品族统一到一起创建;
- 当增加一个新的产品族时不需要修改原代码,满足开闭原则。
2. 抽象工厂模式的缺点有:
- 当产品族中需要增加一个新的产品时,所有的工厂类都需要修改。
2. 模式的结构与实现
抽象工厂模式和工厂方法模式一样,也是由抽象工厂、具体工厂、抽象产品和具体产品组成。但抽象工厂中方法的个数不同,抽象产品的个数也不同。
2.1 模式的定义
抽象工厂模式的主要角色如下:
- 抽象工厂(Abstract Factory):提供了创建产品的接口,它包含了多个创建产品的接口,可以创建多个不同等级的产品;
- 具体工厂(Concrete Factory):实现抽象工厂中的多个抽象方法,完成具体产品的创建;
- 抽象产品(Abstract Product):定义了产品的规范,描述了产品的主要特性和功能,抽象工厂模式有多个抽象产品;
- 抽象产品(Abstract Product):定义了产品的规范,描述了产品的主要特性和功能,抽象工厂模式有多个抽象产品;
- 具体产品(Concrete Product):实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间是多对一的关系。
2.2 模式的实现
抽象产品
/**
* 视频抽象产品类
*/
public abstract class Video {
/**
* 创建视频
*/
public abstract void produce();
}
/**
* 文章抽象产品类
*/
public abstract class Article {
/**
* 创建文章
*/
public abstract void produce();
}
具体产品
/**
* java 视频具体产品
*/
public class JavaVideo extends Video {
@Override
public void produce() {
System.out.println("创建 Java 视频");
}
}
/**
* Java 文章具体产品
*/
public class JavaArticle extends Article {
@Override
public void produce() {
System.out.println("创建 Java 文章");
}
}
/**
* python 视频具体产品
*/
public class PythonVideo extends Video {
@Override
public void produce() {
System.out.println("创建 python 视频");
}
}
/**
* python 文章具体产品
*/
public class PythonArticle extends Article {
@Override
public void produce() {
System.out.println("创建 python 文章");
}
}
抽象工厂
/**
* 课程工厂类,抽象工厂,可以生产不同等级的产品族
*/
public interface CourseFactory {
Video getVideo();
Article getArticle();
}
具体工厂
/**
* Java 课程工厂,具体工厂,生产 Java 视频和 文章
*/
public class JavaCourseFactory implements CourseFactory {
@Override
public Video getVideo() {
return new JavaVideo();
}
@Override
public Article getArticle() {
return new JavaArticle();
}
}
/**
* python 课程工厂,具体工厂,生产 python 课程和文章
*/
public class PythonCourseFactory implements CourseFactory {
@Override
public Video getVideo() {
return new PythonVideo();
}
@Override
public Article getArticle() {
return new PythonArticle();
}
}
客户端
public class Client {
public static void main(String[] args) {
CourseFactory factory = new JavaCourseFactory();
Video video = factory.getVideo();
Article article = factory.getArticle();
video.produce();
article.produce();
factory = new PythonCourseFactory();
video = factory.getVideo();
article = factory.getArticle();
video.produce();
article.produce();
}
}
# 运行结果如下:
创建 Java 视频
创建 Java 文章
创建 python 视频
创建 python 文章
3. 模式在开源软件中的应用
3.1 java.sql.Connection
/**
* 数据连接抽象工厂类,具体工厂类实现自己的数据库连接,如mysql
*/
public interface Connection extends Wrapper, AutoCloseable {
Statement createStatement() throws SQLException;
PreparedStatement prepareStatement(String sql)
throws SQLException;
}
/**
* mysql 数据连接具体工厂类,实现Mysql自己的数据库连接
*/
package com.mysql.jdbc;
public class ConnectionImpl extends ConnectionPropertiesImpl implements Connection {
public Statement createStatement() throws SQLException {
return this.createStatement(1003, 1007);
}
public PreparedStatement prepareStatement(String sql) throws SQLException {
return this.prepareStatement(sql, 1003, 1007);
}
}
3.2 mybaties.SessionFactory
/**
* SqlSessionFactory 抽象工厂类,用来生产 SqlSession,
* DefaultSqlSessionFactory 和 SqlssionManager 就是具体的工厂;
* SqlSession 就是抽象的产品;
* DefaultSqlSession 、SqlSessionManager 和 SqlSessionTemplate 就是具体的工厂;
*/
public interface SqlSessionFactory {
SqlSession openSession();
SqlSession openSession(boolean autoCommit);
SqlSession openSession(Connection connection);
SqlSession openSession(TransactionIsolationLevel level);
SqlSession openSession(ExecutorType execType);
SqlSession openSession(ExecutorType execType, boolean autoCommit);
SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level);
SqlSession openSession(ExecutorType execType, Connection connection);
Configuration getConfiguration();
}