一、概念
顾名思义,工厂模式是用工厂方法代替 new 操作的一种模式。工厂模式可以分为三种类型:简单工厂、工厂方法、抽象工厂。
1.1 简单工厂
定义一个工厂类,根据传入的参数不同返回不同的实例,被创建的实例具有共同的父类或接口。
适用场景
- 由于只有一个工厂类,类的创建不能过于复杂或者创建的类过多
- 使用者不关系类的创建过程
实例:我们根据配置文件中不同的序列化类型,选择不同的序列化的实例对象
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 工厂方法
在工厂方法模式中,针对不同的对象提供不同的工厂,即每个对象都有一个与之对应的工厂。
适用场景
- 对象创建的逻辑较为复杂,可以通过子类工厂创建对应的子类实例
- 使用者不需要了解对象的创建过程
工厂方法和简单工厂的区别:
- 简单工厂只能算一种编程习惯,而不是一种设计模式。而工厂方法算一种设计模式
- 工厂方法为每个对象都创建一个工厂,而简单工厂只创建一个工厂
- 工厂方法中每个工厂都继承了创建对象的接口
实例:通过不同的文件后缀名(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 = ""; RuleConfig ruleConfig = parser.parse(configText); return ruleConfig; }
private String getFileExtension(String filePath) { 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 抽象工厂
抽象工厂中可以让一个工厂负责创建多个不同类型的对象
适用场景
- 工厂类中需要创建一组对象
- 使用者不关心对象的创建过程
实例:现在需要做一款跨平台的游戏,需要兼容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(); } }
|
其他代码和工厂方法的代码类似
工厂方法和抽象工厂的区别?
- 抽象工厂中的子类工厂可以创建一组对象,而工厂方法中的子类工厂只能创建一个对象
二、总结
当对象的创建逻辑比较复杂,是一个大工程的时候,我们就考虑使用工厂模式,封装对象的创建过程,将对象的创建和使用相分离。
比较复杂的场景
- 存在 if-else 分支判断,动态的根据不同的类型创建不同的对象,这时候我们可以考虑将一大堆 if-else 抽离封装到一个工厂类中。
- 单个对象的创建比较复杂,如:需要组合其他对象、做各种初始化操作,这时候我们也可以考虑将其封装到工厂类中。
好处
- 封装后,创建逻辑对调用者更加透明,不需要了解对象复杂的创建过程
- 代码复用:创建代码抽离到独立的工厂类之后可以复用
- 控制复杂度:将创建代码抽离,让本来的函数或类职责单一、代码更加简洁
实例:Java中的 Calender、DateFormat、Excutors,Spring中的 FactoryBean 等
参考资料
- 三分钟快速了解Spring中的工厂模式 - 掘金 (juejin.cn)
- 工厂模式