# 抽象工厂
关联阅读 李兴华-抽象工厂
定义:抽象工厂模式提供一个创建一系列相关或相互依赖对象的接口。
- 无须指定他们具体的类
类型:创建型
# 使用场景
- 客户端(应用层)不依赖于产品类实例如何被创建、实现等细节
- 强调一系列相关的产品对象(属于同一产品族)一起使用创建对象需要大量重复代码
- 提供一个产品类的库,所有的产品以同样的接口出现,从而使客户端不依赖于具体实现
# 优缺点
优点:
- 具体产品在应用层代码隔离,无须关心创建细节
- 将一个系列的产品族统一到一起创建
缺点:
- 规定了所有可能被创建的产品集合,产品族中扩展新的产品困难,需要修改抽象工厂的接口
- 增加了系统的抽象性和理解难度
# 产品登记结构与产品族
产品族:相同颜色的代表一个产品族。
产品等级:形状一样的为产品等级。
如果:第一排,美的电视,美的洗衣机,美的空调。竖着来看(椭圆形),美的空调,海尔空调,格力空调
工厂方法是针对 产品等级结构,抽象工厂针对的是产品族
# coding
场景:慕课网课程不单是 video 了,视频 + 手记( Article ) 才被视为一个课程
// 抽象工厂接口
public abstract class CourseFactory {
abstract Video getVideo();
abstract Article getArticle();
}
// 产品族的产品抽象接口
public abstract class Video {
public abstract void produce();
}
public abstract class Article {
public abstract void produce();
}
// java 抽象工厂实现
public class JavaCourseFactory extends CourseFactory {
@Override
Video getVideo() {
return new JavaVideo();
}
@Override
Article getArticle() {
return new JavaArticle();
}
}
// java 产品
public class JavaVideo extends Video {
@Override
public void produce() {
System.out.println("录制 Java 课程");
}
}
public class JavaArticle extends Article{
@Override
public void produce() {
System.out.println("编写 Java 手记");
}
}
Python 课程的和这个结构一样,就不贴代码了,直接看类图吧
public class Test {
public static void main(String[] args) {
// 通过 java 产品族抽象工厂获取的产品一定都是 java 的产品
CourseFactory factory = new JavaCourseFactory();
Video video = factory.getVideo();
Article article = factory.getArticle();
video.produce();
article.produce();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
依赖关系就是下面这样
可以看到,客户端只依赖抽象工厂,然后获取一系列的产品,比如这里的 java 的产品
如果再增加产品族的话也是比较方便的,符合开闭原则,但是一定要选择适合的场景。
比如:产品族中的产品变更很频繁,今天增加一个,明天增加一个,后天又减少一个 这种的场景就不适合抽象工厂,因为需要在抽象工厂接口中增加或则减少产品, 那么会影响所有的的抽象工厂实现类发生修改。
所以一般会选择相对固定的业务场景
# jdk 中的 源码
java.sql.Connection
public interface Connection extends Wrapper, AutoCloseable {
Statement createStatement() throws SQLException;
PreparedStatement prepareStatement(String sql)
throws SQLException;
java.sql.Statement
// 这个类也是,返回的都是 statement相关的产品
public interface Statement extends Wrapper, AutoCloseable {
ResultSet executeQuery(String sql) throws SQLException;
int executeUpdate(String sql) throws SQLException;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
该接口就是一个抽象工厂的影子,返回的都是某一系列产品族的产品,如果引入了 mysql 驱动包, 就会看到 mysql 实现了该类,返回的肯定都是 mysql 相关的产品
mybatis 的 SqlSessionFactory 也是一个抽象工厂
org.apache.ibatis.session.SqlSessionFactory
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();
}
// DefaultSqlSession 就是一个工厂实现
org.apache.ibatis.session.defaults.DefaultSqlSessionFactory#openSession(boolean)
@Override
public SqlSession openSession(boolean autoCommit) {
return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, autoCommit);
}
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
try {
final Environment environment = configuration.getEnvironment();
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
final Executor executor = configuration.newExecutor(tx, execType);
// 在这里返回了 DefaultSqlSession (SqlSession的实现类)
return new DefaultSqlSession(configuration, executor, autoCommit);
} catch (Exception e) {
closeTransaction(tx); // may have fetched a connection so lets call close()
throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45