工厂模式

一、概念

顾名思义,工厂模式是用工厂方法代替 new 操作的一种模式。工厂模式可以分为三种类型:简单工厂、工厂方法、抽象工厂。

1.1 简单工厂

定义一个工厂类,根据传入的参数不同返回不同的实例,被创建的实例具有共同的父类或接口。

适用场景

  1. 由于只有一个工厂类,类的创建不能过于复杂或者创建的类过多
  2. 使用者不关系类的创建过程

实例:我们根据配置文件中不同的序列化类型,选择不同的序列化的实例对象

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
55
/**
* 序列化接口
*/
public interface RpcSerialization {

<T> byte[] serialize(T obj) throws IOException;

<T> T deserialize(byte[] data, Class<T> clz) throws IOException;
}

/**
* 序列化工厂
*/
public class SerializationFactory {
public static RpcSerialization getRpcSerialization(SerializationTypeEnum typeEnum) {
switch (typeEnum) {
case JSON:
return new JsonSerialization();
case PROTOSTUFF:
return new ProtostuffSerializer();
default:
throw new IllegalArgumentException("serialization type is illegal");
}
}
}

/**
* 序列化实例
*/
public class JsonSerialization implements RpcSerialization {

@Override
public <T> byte[] serialize(T obj) throws IOException {
// 序列化
}

@Override
public <T> T deserialize(byte[] data, Class<T> clz) throws IOException {
// 反序列化
}
}

public class ProtostuffSerializer implements RpcSerialization {

@Override
public <T> byte[] serialize(T obj) throws IOException {
// 序列化
}


@Override
public <T> T deserialize(byte[] data, Class<T> clz) throws IOException {
// 反序列化
}
}

1.2 工厂方法

在工厂方法模式中,针对不同的对象提供不同的工厂,即每个对象都有一个与之对应的工厂。

适用场景

  1. 对象创建的逻辑较为复杂,可以通过子类工厂创建对应的子类实例
  2. 使用者不需要了解对象的创建过程

工厂方法和简单工厂的区别:

  1. 简单工厂只能算一种编程习惯,而不是一种设计模式。而工厂方法算一种设计模式
  2. 工厂方法为每个对象都创建一个工厂,而简单工厂只创建一个工厂
  3. 工厂方法中每个工厂都继承了创建对象的接口

实例:通过不同的文件后缀名(yaml、xml、json),创建不同的解析对象。

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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
public class RuleConfigSource {
public RuleConfig load(String ruleConfigFilePath) {
// 获取文件后缀名
String ruleConfigFileExtension = getFileExtension(ruleConfigFilePath);
// 获取对应的实例工厂
IRuleConfigParserFactory parserFactory = RuleConfigParserFactoryMap.getParserFactory(ruleConfigFileExtension);
if (parserFactory == null) {
throw new InvalidRuleConfigException("Rule config file format is not support!");
}
// 创建对应的实例
IRuleConfigParser parser = parserFactory.createParser();
String configText = "";
//从ruleConfigFilePath文件中读取配置文本到configText中
RuleConfig ruleConfig = parser.parse(configText);
return ruleConfig;
}

private String getFileExtension(String filePath) {
//...解析文件名获取扩展名,比如rule.json,返回json
return "json";
}
}

// 因为工厂类只包含方法,不包含成员变量,完全可以复用,
// 不需要每次都创建新的工厂类对象,所以,工厂方法模式的思路更加合适
// 工厂的工厂
public class RuleConfigParserFactoryMap {
private static final Map<String, IRuleConfigParserFactory> cachedFactories = new HashMap<>();

static {
cachedFactories.put("json", new JsonRuleConfigParserFactory());
cachedFactories.put("xml", new XmlRuleConfigParserFactory());
cachedFactories.put("yaml", new YamlRuleConfigParserFactory());
cachedFactories.put("properties", new PropertiesRuleConfigParserFactory())
}

public static IRuleConfigParserFactory getParserFactory(String type) {
if (type == null || type.isEmpty()) {
return null;
}
IRuleConfigParserFactory parserFactory = cachedFactories.get(type.toLowerCase());
return parserFactory;
}
}

// 创建实例的接口
public interface IRuleConfigParserFactory {
IRuleConfigParser createParser();
}

// 解析器工厂
public class JsonRuleConfigParserFactory implements IRuleConfigParserFactory {
@Override
public IRuleConfigParser createParser() {
return new JsonRuleConfigParser();
}
}

public class YamlRuleConfigParserFactory implements IRuleConfigParserFactory {
@Override
public IRuleConfigParser createParser() {
return new YamlRuleConfigParser();
}
}

public class PropertiesRuleConfigParserFactory implements IRuleConfigParserFactory {
@Override
public IRuleConfigParser createParser() {
return new PropertiesRuleConfigParser();
}
}

1.3 抽象工厂

抽象工厂中可以让一个工厂负责创建多个不同类型的对象

适用场景

  1. 工厂类中需要创建一组对象
  2. 使用者不关心对象的创建过程

实例:现在需要做一款跨平台的游戏,需要兼容Android,Ios,Wp三个移动操作系统,该游戏针对每个系统都设计了一套操作控制器(OperationController)和界面控制器(UIController)

1
2
3
4
5
6
7
8
9
10
11
public class WpFactory implements SystemFactory {
@Override
public OperationController createOperationController() {
return new WpOperationController();
}

@Override
public UIController createInterfaceController() {
return new WpUIController();
}
}

其他代码和工厂方法的代码类似

工厂方法和抽象工厂的区别?

  1. 抽象工厂中的子类工厂可以创建一组对象,而工厂方法中的子类工厂只能创建一个对象

二、总结

当对象的创建逻辑比较复杂,是一个大工程的时候,我们就考虑使用工厂模式,封装对象的创建过程,将对象的创建和使用相分离。

比较复杂的场景

  1. 存在 if-else 分支判断,动态的根据不同的类型创建不同的对象,这时候我们可以考虑将一大堆 if-else 抽离封装到一个工厂类中。
  2. 单个对象的创建比较复杂,如:需要组合其他对象、做各种初始化操作,这时候我们也可以考虑将其封装到工厂类中。

好处

  1. 封装后,创建逻辑对调用者更加透明,不需要了解对象复杂的创建过程
  2. 代码复用:创建代码抽离到独立的工厂类之后可以复用
  3. 控制复杂度:将创建代码抽离,让本来的函数或类职责单一、代码更加简洁

实例:Java中的 Calender、DateFormat、Excutors,Spring中的 FactoryBean 等

参考资料

  1. 三分钟快速了解Spring中的工厂模式 - 掘金 (juejin.cn)
  2. 工厂模式

工厂模式
https://pursuemilk.github.io/2023/03/26/工厂模式/
作者
PursueMilk
发布于
2023年3月26日
许可协议