abstract_factory
# 抽象工厂模式
# 模式引入
# 问题描述
数据库是应用中不可缺少的组件,假设我们的应用最开始时使用 MySQL,但是某一天突然需要接一个 Access,两个数据库在很多方面都不相同,原来的创建、更新、删除、查询相关代码都需要修改。最简单的方案是直接针对 Access 重新写一套,最外面用一个参数来判断是使用哪种库,并路由到对应的逻辑。
但是好景不长,又接到了一个 Oracle,这时候怎么办,再写一套新的,再多一个判断分支?当然也未尝不可。但这种情况已经出现两次了,聪明的你可能已经意识到了,万一过几天再来一个新的怎么办,干脆将业务逻辑和具体的库隔离开。
# 模式定义
当有多个产品或相关产品系列时,通过组合的方式将创建对象的任务委托给其他类,可以保证多个或系列产品的一致性。也使得交换产品系列更加方便,一个具体工厂只在初始化时出现一次,只需修改这里就可以使用不同的产品配置。
抽象工厂模式提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们的具体类。它是一般化的工厂方法,可以看做一组工厂方法的集合。
# 问题分析
我们用抽象工厂模式重新设计开始时的问题。就是把增删改查的逻辑抽离出来,与实际的数据库解耦,我们通过新创建一个对应数据库(比如 MySQL)的工厂,该工厂新建、更新和删除的每张表都是与该数据库相对应的,它们都接受相同的业务参数。
# 模式介绍
# 解决方案
我们以 User 表和 Department 两张表为例。
- 首先需要一个
Factory的接口类,定义createProduct方法:createUser和createDepartment。 - 针对不同的数据库实现对应的
ConcreteFactory:SqlServerFactory和AccessFactory,然后通过重写上面的两个方法,使其可以创建对应数据库的不同表(产品)。 - 对不同的产品创建
Product的接口类:Department和User,定义insert和对应的getProduct方法。 - 创建对应的
ConcreteProduct,并重写自己的插入方法。
下面是一些注意事项:
- 可以借助反射使用变量来初始化不同产品,以减少显式、固定地分支判断。
- 可以根据需要与简单工厂、工厂方法结合起来使用。
- 一般不在开发初期使用,通常从简单工厂或工厂方法开始。
# 代码实现
Factory 类:
public interface Factory {
User createUser();
Department createDepartment();
}
1
2
3
4
2
3
4
ConcreteFactory 类:
public class SqlServerFactory implements Factory {
@Override
public User createUser() {
return new SqlServerUser();
}
@Override
public Department createDepartment() {
return new SqlserverDepartment();
}
}
public class AccessFactory implements Factory {
@Override
public User createUser() {
return new AccessUser();
}
@Override
public Department createDepartment() {
return new AccessDepartment();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Product 类:
public interface User {
void insert(User user);
User getUser(int id);
}
public interface Department {
void Insert(Department department);
Department getDepartment(int id);
}
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
ConcreteProduct 类:
public class SqlServerUser implements User {
@Override
public void insert(User user) {
System.out.println("在SQL Server中给User表增加一条记录");
}
@Override
public User getUser(int id) {
System.out.println("在SQL Server中根据ID得到User表一条记录");
return null;
}
}
public class AccessUser implements User {
@Override
public void insert(User user) {
System.out.println("在Access中给User表增加一条记录");
}
@Override
public User getUser(int id) {
System.out.println("在Access中根据ID得到User表一条记录");
return null;
}
}
public class SqlserverDepartment implements Department{
@Override
public void Insert(Department department) {
System.out.println("在SQL Server中给Department表增加一条记录");
}
@Override
public Department getDepartment(int id) {
System.out.println("在SQL Server中根据ID得到Department表一条记录");
return null;
}
}
public class AccessDepartment implements Department {
@Override
public void Insert(Department department) {
System.out.println("在Access中给Department表增加一条记录");
}
@Override
public Department getDepartment(int id) {
System.out.println("在Access中根据ID得到Department表一条记录");
return null;
}
}
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
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
Main 方法:
public class Main {
public static void main(String[] args) {
User user = new AccessUser();
Department dept = new AccessDepartment();
Factory factory = new AccessFactory();
User iu = factory.createUser();
iu.insert(user);
iu.getUser(1);
Department department = factory.createDepartment();
department.Insert(dept);
department.getDepartment(1);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
执行结果:
在Access中给User表增加一条记录
在Access中根据ID得到User表一条记录
在Access中给Department表增加一条记录
在Access中根据ID得到Department表一条记录
1
2
3
4
2
3
4
# 结构组成

- AbstractFactory:抽象工厂,分别对应不同的序列(如上面不同的数据库)。
- ConcreateFactory:抽象工厂的具体实现,不同的工厂会创建不同的产品系列。
- AbstractProduct:抽象产品,分别有不同的实现(比如上面的 User 和 Department)。
- ConcreteProduct:抽象产品的具体实现。
# 模式评价
# 适用场景
- 需要使用大量工厂方法生产系列产品时。比如上面例子中的多个数据库。
- 需要独立于产品的创建、组合和表示时。
- 需要将产品类库的接口和实现分离时。比如上面例子中的两张表。
# 实际应用
实际中的例子:极少扩展的产品系列。
- 数据库。
- 标准用户界面工具包。
- 汽车部件。
- 游戏环境。
# 优点缺点
抽象工厂模式优点包括:
- 将产品和生成产品分开,工厂不同,产品不同,易于维护。
- 具体实例创建与客户端解耦,客户端不关心具体工厂。
抽象工厂模式缺点包括:
- 难以支持新种类的产品,因为扩展新类需要扩展工厂接口,涉及到所有子类的改变。比如我们新增了一张 Project 表,那就需要在所有地方都实现一遍。
上次更新: 2025-02-06 00:56:14