设计模式07 - 设计模式 - 工厂设计模式(高频-创建型)

工厂设计模式

一、定义

  一般情况下,工厂模式分为三种更加细分的类型:简单工厂、工厂方法和抽象工厂

二、实现方式

2.1 简单工厂模式

  在下面这段代码中,我们根据配置文件的后缀(json、xml、yaml、properties),选择不同的解析器(JsonRuleConfigParser、XmlRuleConfigParser……)

复制代码
 1   public IRuleConfigParser createParser(String configFormat) {
 2     IRuleConfigParser parser = null;
 3     if ("json".equalsIgnoreCase(configFormat)) {
 4       parser = new JsonRuleConfigParser();
 5     } else if ("xml".equalsIgnoreCase(configFormat)) {
 6       parser = new XmlRuleConfigParser();
 7     } else if ("yaml".equalsIgnoreCase(configFormat)) {
 8       parser = new YamlRuleConfigParser();
 9     }
10     return parser;
11   }
12 }
复制代码

  总结一下,尽管简单工厂模式的代码实现中,有多处 if 分支判断逻辑,违背开闭原则,但权衡扩展性和可读性,这样的代码实现在大多数情况下(比如,不需要频繁地添加 parser,也没有太多的 parser)是没有问题的。

2.2 工厂方法(Factory Method)

  如果我们非得要将 if 分支逻辑去掉,那该怎么办呢?比较经典处理方法就是利用多态。按照多态的实现思路,对上面的代码进行重构。重构后就是工厂方法。

复制代码
 1 public interface IRuleConfigParserFactory {
 2   IRuleConfigParser createParser();
 3 }
 4 public class JsonRuleConfigParserFactory implements IRuleConfigParserFactory {
 5   @Override
 6   public IRuleConfigParser createParser() {
 7     return new JsonRuleConfigParser();
 8   }
 9 }
10 public class XmlRuleConfigParserFactory implements IRuleConfigParserFactory {
11   @Override
12   public IRuleConfigParser createParser() {
13     return new XmlRuleConfigParser();
14   }
15 }
16 public class YamlRuleConfigParserFactory implements IRuleConfigParserFactory {
17   @Override
18   public IRuleConfigParser createParser() {
19     return new YamlRuleConfigParser();
20   }
21 }
复制代码

  这样当我们新增一种 parser 的时候,只需要新增一个实现了 IRuleConfigParserFactory 接口的 Factory 类即可。所以,工厂方法模式比起简单工厂模式更加符合开闭原则。但是,使用那些工厂类,又需要判断。代码如下:

复制代码
 1 public class RuleConfigSource {
 2   public IRuleConfigParser load() {
 3     IRuleConfigParserFactory parserFactory = null;
 4       /*******************
 5       *这里还是需要根据文件名去判断,进而使用哪一个工厂方法
 6       ********************/
 7     if ("json".equalsIgnoreCase("json")) {
 8       parserFactory = new JsonRuleConfigParserFactory();
 9     } else if ("xml".equalsIgnoreCase(ruleConfigFileExtension)) {
10       parserFactory = new XmlRuleConfigParserFactory();
11     } else if ("yaml".equalsIgnoreCase(ruleConfigFileExtension)) {
12       parserFactory = new YamlRuleConfigParserFactory();
13     } 
14     IRuleConfigParser parser = parserFactory.createParser();
15     return parser;
16   }
17 }
复制代码

  工厂方法 VS 简单工厂模式

  我们前面提到,之所以将某个代码块剥离出来,独立为函数或者类,原因是这个代码块的逻辑过于复杂,剥离之后能让代码更加清晰,更加可读、可维护。但是,如果代码块本身并不复杂,就几行代码而已,我们完全没必要将它拆分成单独的函数或者类。基于这个设计思想,当对象的创建逻辑比较复杂,不只是简单的 new 一下就可以,而是要组合其他类对象,做各种初始化操作的时候,我们推荐使用工厂方法模式;简单的if -else就OK的就简单工厂模式

2.3抽象工厂(工厂方法的集合)

  抽象工厂可以看成是工厂方法的集合。抽象工厂模式的应用场景比较特殊,没有前两种常用。在简单工厂和工厂方法中,类只有一种分类方式。比如,在规则配置解析那个例子中,解析器类只会根据配置文件格式(Json、Xml、Yaml……)来分类。但是,如果类有两种分类方式,比如,我们既可以按照配置文件格式来分类,也可以按照解析的对象(Rule 规则配置还是 System 系统配置)来分类,那就会对应下面这 8 个 parser 类。

针对规则配置的解析器:基于接口IRuleConfigParser
JsonRuleConfigParser
XmlRuleConfigParser
YamlRuleConfigParser
PropertiesRuleConfigParser
针对系统配置的解析器:基于接口ISystemConfigParser
JsonSystemConfigParser
XmlSystemConfigParser
YamlSystemConfigParser
PropertiesSystemConfigParser

  针对这种特殊的场景,如果还是继续用工厂方法来实现的话,我们要针对每个 parser 都编写一个工厂类,也就是要编写 8 个工厂类。如果我们未来还需要增加针对业务配置的解析器(比如 IBizConfigParser),那就要再对应地增加 4 个工厂类。而我们知道,过多的类也会让系统难维护。这个问题该怎么解决呢?抽象工厂就是针对这种非常特殊的场景而诞生的。我们可以让一个工厂负责创建多个不同类型的对象(IRuleConfigParser、ISystemConfigParser 等),而不是只创建一种 parser 对象。这样就可以有效地减少工厂类的个数。具体的代码实现如下所示:

复制代码
 1 public interface IConfigParserFactory {
 2   IRuleConfigParser createRuleParser();
 3   ISystemConfigParser createSystemParser();
 4   //此处可以扩展新的parser类型,比如IBizConfigParser
 5 }
 6 public class JsonConfigParserFactory implements IConfigParserFactory {
 7   @Override
 8   public IRuleConfigParser createRuleParser() {
 9     return new JsonRuleConfigParser();
10   }
11   @Override
12   public ISystemConfigParser createSystemParser() {
13     return new JsonSystemConfigParser();
14   }
15 }
16 public class XmlConfigParserFactory implements IConfigParserFactory {
17   @Override
18   public IRuleConfigParser createRuleParser() {
19     return new XmlRuleConfigParser();
20   }
21   @Override
22   public ISystemConfigParser createSystemParser() {
23     return new XmlSystemConfigParser();
24   }
25 }
26 // 省略YamlConfigParserFactory和PropertiesConfigParserFactory代码
复制代码

三、使用场景(待补充)

posted @   云执  阅读(30)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· Vue3状态管理终极指南:Pinia保姆级教程
点击右上角即可分享
微信分享提示