一般情况下,工厂模式分为三种更加细分的类型:简单工厂、工厂方法和抽象工厂。在 GoF 的《设计模式》一书中,它将简单工厂模式看作是工厂方法模式的一种特例,所以工厂模式只被分成了工厂方法和抽象工厂两类。
1. 简单工厂
1.1 简单工厂的实现方式
type ConfigParser interface {
Parse(content string) (interface{}, error)
}
type (
JsonRuleConfigParser struct{}
XmlRuleConfigParser struct{}
YamlRuleConfigParser struct{}
PropertiesRuleConfigParser struct{}
)
func (j JsonRuleConfigParser) Parse(content string) (interface{}, error) {
//TODO implement me
panic("implement me")
}
func (x XmlRuleConfigParser) Parse(content string) (interface{}, error) {
//TODO implement me
panic("implement me")
}
func (y YamlRuleConfigParser) Parse(content string) (interface{}, error) {
//TODO implement me
panic("implement me")
}
func (p PropertiesRuleConfigParser) Parse(content string) (interface{}, error) {
//TODO implement me
panic("implement me")
}
type ConfigParserFactory struct {
}
func (c ConfigParserFactory) CreateConfigParser(fileExtension string) (ConfigParser, error) {
var parser ConfigParser
if fileExtension == "json" {
parser = JsonRuleConfigParser{}
} else if fileExtension == "xml" {
parser = XmlRuleConfigParser{}
} else if fileExtension == "yaml" {
parser = YamlRuleConfigParser{}
} else if fileExtension == "properties" {
parser = PropertiesRuleConfigParser{}
} else {
return nil, errors.New("unsupported file extension")
}
return parser, nil
}
大部分工厂类都是以“Factory”这个单词结尾的。实际上,如果 parser 可以复用,为了节省内存和对象创建的时间,我们可以将 parser 事先创建好缓存起来。
var cachedParsers map[string]ConfigParser
func init() {
cachedParsers = make(map[string]ConfigParser)
cachedParsers["json"] = JsonRuleConfigParser{}
cachedParsers["xml"] = XmlRuleConfigParser{}
cachedParsers["yaml"] = YamlRuleConfigParser{}
cachedParsers["properties"] = PropertiesRuleConfigParser{}
}
func (c ConfigParserFactory) CreateConfigParserWithCache(fileExtension string) (ConfigParser, error) {
parser, ok := cachedParsers[fileExtension]
if ok {
return parser, nil
}
return nil, errors.New("unsupported file extension")
}
如果 if 分支并不是很多,代码中有 if 分支也是完全可以接受的。应用多态或设计模式来替代 if 分支判断逻辑,也并不是没有任何缺点的,它虽然提高了代码的扩展性,更加符合开闭原则,但也增加了类的个数,牺牲了代码的可读性。
尽管简单工厂模式的代码实现中,有多处 if 分支判断逻辑,违背开闭原则,但权衡扩展性和可读性,这样的代码实现在大多数情况下是没有问题的。
2. 工厂方法
2.1 工厂方法的实现
如果创建单个 parser 的过程进一步复杂化,则需要单独的工厂来实现。当新增一种 parser 的时候,只需要新增一个实现了 IRuleConfigParserFactory 接口的 Factory 类即可。所以,工厂方法模式比起简单工厂模式更加符合开闭原则。
type IConfigParserFactory interface {
CreateParser() ConfigParser
}
type (
JsonRuleConfigParserFactory struct {
}
XmlRuleConfigParserFactory struct {
}
YamlRuleConfigParserFactory struct {
}
PropertiesRuleConfigParserFactory struct {
}
)
func (j JsonRuleConfigParserFactory) CreateParser() ConfigParser {
return JsonRuleConfigParser{}
}
func (x XmlRuleConfigParserFactory) CreateParser() ConfigParser {
return XmlRuleConfigParser{}
}
func (y YamlRuleConfigParserFactory) CreateParser() ConfigParser {
return YamlRuleConfigParser{}
}
func (p PropertiesRuleConfigParserFactory) CreateParser() ConfigParser {
return PropertiesRuleConfigParser{}
}
// ConfigParserSource 是创建工厂对象的工厂类
type ConfigParserSource struct {
}
func (c *ConfigParserSource) CreateConfigParser(fileExtension string) (ConfigParser, error) {
var factory IConfigParserFactory
if fileExtension == "json" {
factory = JsonRuleConfigParserFactory{}
} else if fileExtension == "xml" {
factory = XmlRuleConfigParserFactory{}
} else if fileExtension == "yaml" {
factory = YamlRuleConfigParserFactory{}
} else if fileExtension == "properties" {
factory = PropertiesRuleConfigParserFactory{}
} else {
return nil, errors.New("unsupported file extension")
}
parser := factory.CreateParser()
return parser, nil
}
var cachedFactories map[string]IConfigParserFactory
func init() {
cachedFactories = make(map[string]IConfigParserFactory)
cachedFactories["json"] = JsonRuleConfigParserFactory{}
cachedFactories["xml"] = XmlRuleConfigParserFactory{}
cachedFactories["yaml"] = YamlRuleConfigParserFactory{}
cachedFactories["properties"] = PropertiesRuleConfigParserFactory{}
}
func (c *ConfigParserSource) CreateConfigParserWithCache(fileExtension string) (ConfigParser, error) {
factory, ok := cachedFactories[fileExtension]
if !ok {
return nil, errors.New("unsupported file extension")
}
parser := factory.CreateParser()
return parser, nil
}
从上面的工厂方法的实现来看,一切都很完美,但是实际上存在挺大的问题。问题存在于这些工厂类的使用上。可以为工厂类再创建一个简单工厂,也就是工厂的工厂,用来创建工厂类对象。
2.1 简单工厂 vs 工厂方法
工厂模式需要额外创建诸多 Factory 类,也会增加代码的复杂性,而且,每个 Factory 类只是做简单的 new 操作,功能非常单薄(只有一行代码),也没必要设计成独立的类。如果每个类功能很单薄,那就没必要设计成独立的类,这时候用简单工厂模式就好,不必要用工厂方法。
当对象的创建逻辑比较复杂,不只是简单的 new 一下就可以,而是要组合其他类对象,做各种初始化操作的时候,推荐使用工厂方法模式,将复杂的创建逻辑拆分到多个工厂类中,让每个工厂类都不至于过于复杂。而使用简单工厂模式,将所有的创建逻辑都放到一个工厂类中,会导致这个工厂类变得很复杂。
如果对象不可复用,那工厂类每次都要返回不同的对象。如果使用简单工厂模式来实现,就只能选择第一种包含 if 分支逻辑的实现方式。我们还想避免烦人的 if-else 分支逻辑,这个时候,就推荐使用工厂方法模式。
3. 抽象工厂
类只有一种分类方式。比如,在规则配置解析那个例子中,解析器类只会根据配置文件格式(Json、Xml、Yaml……)来分类。但是,如果类有两种分类方式,比如,既可以按照配置文件格式来分类,也可以按照解析的对象(Rule 规则配置还是 System 系统配置)来分类。那就会额外新增 8 个 parser,如果还是继续用工厂方法来实现的话,要针对每个 parser 都编写一个工厂类,也就是要编写 8 个工厂类。
抽象工厂就是针对这种非常特殊的场景而诞生的。可以让一个工厂负责创建多个不同类型但又相关的对象(IRuleConfigParser、ISystemConfigParser 等),而不是只创建一种 parser 对象。
type IConfigParserFactory interface {
CreateRuleParser() simple_factory.RuleConfigParser //
CreateSystemParser() ISystemConfigParser
}
type (
JsonRuleConfigParserFactory struct {
}
XmlRuleConfigParserFactory struct {
}
YamlRuleConfigParserFactory struct {
}
PropertiesRuleConfigParserFactory struct {
}
)
func (j JsonRuleConfigParserFactory) CreateRuleParser() simple_factory.RuleConfigParser {
return simple_factory.JsonRuleConfigParser{}
}
func (j JsonRuleConfigParserFactory) CreateSystemParser() ISystemConfigParser {
return JsonSystemConfigParser{}
}
func (x XmlRuleConfigParserFactory) CreateRuleParser() simple_factory.RuleConfigParser {
return simple_factory.XmlRuleConfigParser{}
}
func (x XmlRuleConfigParserFactory) CreateSystemParser() ISystemConfigParser {
return XmlSystemConfigParser{}
}
func (y YamlRuleConfigParserFactory) CreateRuleParser() simple_factory.RuleConfigParser {
return simple_factory.YamlRuleConfigParser{}
}
func (y YamlRuleConfigParserFactory) CreateSystemParser() ISystemConfigParser {
return YamlSystemConfigParser{}
}
func (p PropertiesRuleConfigParserFactory) CreateRuleParser() simple_factory.RuleConfigParser {
return simple_factory.PropertiesRuleConfigParser{}
}
func (p PropertiesRuleConfigParserFactory) CreateSystemParser() ISystemConfigParser {
return PropertiesSystemConfigParser{}
}
// ConfigParserSource 是创建工厂对象的工厂类
type ConfigParserSource struct {
}
func (c *ConfigParserSource) CreateConfigParser(fileExtension, configType string) (interface{}, error) {
if configType == "rule" {
return c.createRuleConfigParser(fileExtension)
}
if configType == "system" {
return c.createSystemConfigParser(fileExtension)
}
return nil, errors.New("unsupported config type")
}
func (c *ConfigParserSource) createRuleConfigParser(fileExtension string) (simple_factory.RuleConfigParser, error) {
var factory IConfigParserFactory
if fileExtension == "json" {
factory = JsonRuleConfigParserFactory{}
} else if fileExtension == "xml" {
factory = XmlRuleConfigParserFactory{}
} else if fileExtension == "yaml" {
factory = YamlRuleConfigParserFactory{}
} else if fileExtension == "properties" {
factory = PropertiesRuleConfigParserFactory{}
} else {
return nil, errors.New("unsupported file extension")
}
return factory.CreateRuleParser(), nil
}
func (c *ConfigParserSource) createSystemConfigParser(fileExtension string) (ISystemConfigParser, error) {
var factory IConfigParserFactory
if fileExtension == "json" {
factory = JsonRuleConfigParserFactory{}
} else if fileExtension == "xml" {
factory = XmlRuleConfigParserFactory{}
} else if fileExtension == "yaml" {
factory = YamlRuleConfigParserFactory{}
} else if fileExtension == "properties" {
factory = PropertiesRuleConfigParserFactory{}
} else {
return nil, errors.New("unsupported file extension")
}
return factory.CreateSystemParser(), nil
}
var cachedFactories map[string]IConfigParserFactory
func init() {
cachedFactories = make(map[string]IConfigParserFactory)
cachedFactories["json"] = JsonRuleConfigParserFactory{}
cachedFactories["xml"] = XmlRuleConfigParserFactory{}
cachedFactories["yaml"] = YamlRuleConfigParserFactory{}
cachedFactories["properties"] = PropertiesRuleConfigParserFactory{}
}
func (c *ConfigParserSource) createRuleConfigParserWithCache(fileExtension string) (simple_factory.RuleConfigParser, error) {
factory, ok := cachedFactories[fileExtension]
if !ok {
return nil, errors.New("unsupported file extension")
}
parser := factory.CreateRuleParser()
return parser, nil
}
func (c *ConfigParserSource) createSystemConfigParserWithCache(fileExtension string) (ISystemConfigParser, error) {
factory, ok := cachedFactories[fileExtension]
if !ok {
return nil, errors.New("unsupported file extension")
}
parser := factory.CreateSystemParser()
return parser, nil
}
type ISystemConfigParser interface {
Parse(content string) ([]byte, error)
}
type (
JsonSystemConfigParser struct {
}
XmlSystemConfigParser struct {
}
YamlSystemConfigParser struct {
}
PropertiesSystemConfigParser struct {
}
)
func (j JsonSystemConfigParser) Parse(content string) ([]byte, error) {
//TODO implement me
panic("implement me")
}
func (x XmlSystemConfigParser) Parse(content string) ([]byte, error) {
//TODO implement me
panic("implement me")
}
func (y YamlSystemConfigParser) Parse(content string) ([]byte, error) {
//TODO implement me
panic("implement me")
}
func (p PropertiesSystemConfigParser) Parse(content string) ([]byte, error) {
//TODO implement me
panic("implement me")
}