源码地址|https://github.com/DingMouRen/DesignPattern
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 创建对象的代码抽离出来,放到工厂类中。
- 尽管我们不需要根据不同的类型创建不同的对象,但是,单个对象本身的创建过程比较复杂,比如前面提到的要组合其他类对象,做各种初始化操作。在这种情况下,我们也可以考虑使用工厂模式,将对象的创建过程封装到工厂类中
对于第一种情况,当每个对象的创建逻辑都比较简单的时候,我推荐使用简单工厂模式,将多个对象的创建逻辑放到一个工厂类中。当每个对象的创建逻辑都比较复杂的时候,为了避免设计一个过于庞大的简单工厂类,我推荐使用工厂方法模式,将创建逻辑拆分得更细,
每个对象的创建逻辑独立到各自的工厂类中。同理,对于第二种情况,因为单个对象本身的创建逻辑就比较复杂,所以,建议使用工厂方法模式.