工厂方法模式(由子类决定要创建的具体类是哪一个)

源码地址|https://github.com/DingMouRen/DesignPattern

工厂方法模式.jpg

IRuleConfigParser: 针对规则配置解析器的抽象,声明解析器解析的方法
JsonRuleConfigParser: json规则配置解析器的解析具体实现
IRuleConfigParserFactory::定义针对规则配置解析器工厂的接口,声明了创建解析器工厂的方法
JsonRuleConfigParserFactory:是IRuleConfigParserFactory的实现类,具体实现了创建解析器的过程。
RuleConfigParserFactoryMap:来负责不同解析器工厂的创建。

定义

工厂方法模式定义一个用于创建对象的接口,让子类决定实例化哪一个类。(简单工厂模式是一个工厂负责所有产品的生产,工厂方法模式是有多个工厂,每个工厂负责一种产品的生产,再由一个管理工厂来负责指定到底哪个工厂来生产)。

业务场景

根据配置文件的后缀(json、xml、yaml、properties),选择不同的解析器(JsonRuleConfigParser、XmlRuleConfigParser……),
将存储在文件中的配置解析成内存对象 RuleConfig。

IRuleConfigParser:针对规则配置解释器的抽象接口,声明解释器需要实现的功能。相当于定义产品的接口。

/**
 *
 * 针对规则配置的解析器:基于接口IRuleConfigParser
 */
public interface IRuleConfigParser {

    RuleConfig parse(String configFormat);
}

JsonRuleConfigParser:实现接口IRuleConfigParser,是规则配置解释器的具体实现。相当于产品的具体实现,当然还有其他的产品:XmlRuleConfigParser YamlRuleConfigParser PropertiesRuleConfigParser.
public class JsonRuleConfigParser implements IRuleConfigParser {
    @Override
    public RuleConfig parse(String configFormat) {
        return null;
    }
}

IRuleConfigParserFactory:工厂的抽象接口,所有的工厂类都需要实现此接口,也就是生产解析器。

public interface IRuleConfigParserFactory {

    IRuleConfigParser createParser();
}

JsonRuleConfigParserFactory:具体的工厂类,实现接口,此处生产JsonRuleConfigParser解析器,不同工厂负责生产的解析器不同。还有其他的工厂:

XmlRuleConfigParserFactory YamlRuleConfigParserFactory PropertiesRuleConfigParserFactory

public class JsonRuleConfigParserFactory implements IRuleConfigParserFactory {
    @Override
    public IRuleConfigParser createParser() {
        return new JsonRuleConfigParser();
    }
}

RuleConfigParserFactoryMap:管理工厂类,负责指定创建什么样的工厂来生产。

/**
 
 * 因为工厂类只包含方法,不包含成员变量,完全可以复用,不需要每次都创建新的工厂类对象,
 * 所以,简单工厂模式的第二种实现思路更加合适
 */
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 (null == type || type.isEmpty()) return null;

        IRuleConfigParserFactory parserFactory = cachedFactories.get(type.toLowerCase());

        return parserFactory;
    }
}

RuleConfigSource:调用者

public class RuleConfigSource {

    public RuleConfig load(String ruleConfigFilePath){

        String ruleConfigFileExtension = getFileExtension(ruleConfigFilePath);

        IRuleConfigParserFactory parserFactory = RuleConfigParserFactoryMap.getParserFactory(ruleConfigFileExtension);

        if (null == parserFactory) throw new IllegalArgumentException("Rule config file format is not supported: " + ruleConfigFilePath);

        IRuleConfigParser parser = parserFactory.createParser();
        /*
            伪代码:读取配置文件中的内容并赋值给configContent字段
         */
        String configContent = "";

        RuleConfig ruleConfig = parser.parse(configContent);

        return ruleConfig;
    }

    /**
     * 解析文件名获取扩展名,比如rule.json,返回json
     * @param ruleConfigFilePath
     * @return
     */
    private String getFileExtension(String ruleConfigFilePath) {
        /*
        解析文件名获取扩展名的业务代码
         */
        return "json";
    }
}

对于规则配置文件解析这个应用场景来说,工厂模式需要额外创建诸多 Factory 类,也会增加代码的复杂性,而且,每个 Factory 类只是做简单的 new 操作,功能非常单薄(只有一行代码),也没必要设计成独立的类,所以,在这个应用场景下,简单工厂模式简单好用,比工厂方法模式更加合适。

什么时候用简单工厂,什么时候用工厂方法模式呢?

之所以将某个代码块剥离出来,独立为函数或类,原因是这段代码的逻辑过于复杂,剥离之后让代码更加清晰、更加可读、可维护。但是,如果代码块本身并不复杂,就几行代码而已,没必要将它拆分成单独的函数或类,使用简单工厂更加简便。当对象的创建逻辑比较复杂,需要组合其他类对象,做各种初始化操作的场景,推荐使用工厂方法模式,将复杂的创建逻辑拆分到多个工厂类中,让每个工厂类都不至于过于复杂;而使用简单工厂模式,将所有的创建逻辑都放在一个工厂类中,会导致这个工厂类变得复杂。

何为创建逻辑比较复杂呢?

  • 第一种情况:类似规则配置解析的例子,代码中存在 if-else 分支判断,动态地根据不同的类型创建不同的对象。针对这种情况,我们就考虑使用工厂模式,将这一大坨 if-else 创建对象的代码抽离出来,放到工厂类中。
  • 尽管我们不需要根据不同的类型创建不同的对象,但是,单个对象本身的创建过程比较复杂,比如前面提到的要组合其他类对象,做各种初始化操作。在这种情况下,我们也可以考虑使用工厂模式,将对象的创建过程封装到工厂类中

对于第一种情况,当每个对象的创建逻辑都比较简单的时候,我推荐使用简单工厂模式,将多个对象的创建逻辑放到一个工厂类中。当每个对象的创建逻辑都比较复杂的时候,为了避免设计一个过于庞大的简单工厂类,我推荐使用工厂方法模式,将创建逻辑拆分得更细,
每个对象的创建逻辑独立到各自的工厂类中。同理,对于第二种情况,因为单个对象本身的创建逻辑就比较复杂,所以,建议使用工厂方法模式.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容