当前位置: 首页 > news >正文

重修设计模式-创建型-工厂模式

重修设计模式-创建型-工厂模式

一、概述

工厂模式(Factory Pattern)是设计模式中非常基础且常用的一种模式,主要目的是通过封装对象的创建过程,从而实现代码的解耦和灵活性的提升。

工厂模式的核心思想

  • 封装对象的创建:将对象的创建过程封装起来,使得客户端不必直接创建对象,而是通过工厂类来间接创建对象。
  • 解耦:将对象的创建与使用分离,使得客户端只需要知道如何使用对象,而不需要知道如何创建对象。
  • 提高扩展性:当需要增加新的产品类时,只需要增加一个具体的工厂类或产品类,而不需要修改原有代码,符合开闭原则(对扩展开放,对修改关闭)。

工厂模式又细分为三种类型,简单工厂工厂方法抽象工厂,其中工厂方法和抽象工厂被收录在23种设计模式中,而简单工厂被看做是工厂方法的一种特例。其实这三种工厂模式的原理和实现都非常简单,重点在于搞清应用场景,什么时候可以考虑使用工厂模式,又该用这三种类型的哪一种呢?

举个例子:

应用需要根据传入的路径去解析文件并显示,但文件可能有json、xml或yaml等格式,需要根据后缀名来创建解析实现类。

需求很简单,可以直接翻译成代码:

fun loadConfig(path: String): Config? {var parser : IRuleConfigParser? = nullif (path.endsWith("json", true)) {parser = JsonRuleParser()} else if (path.endsWith("xml", true)) {parser = XmlRuleParser()} else if (path.endsWith("yaml", true)) {parser = YamlRuleParser()}val config = parser?.parser(path)return config
}

但“根据文件后缀名创建解析器”的逻辑是相对独立的,可以将其抽成一个方法来复用,但其实还可以将这部分逻辑抽成一个类,让这个类来负责对象的创建,从而更符合单一职责原则,让代码更清晰,而抽出的类就是简单工厂模式了。

二、简单工厂(Simple Factory)

又称静态工厂方法模式(Static Factory Method Pattern),简单工厂模式不是一种设计模式,而更像是一种编程习惯。抽出的工厂类根据传入的参数,决定创建出哪一种类的实例。

下面用简单工厂封装一下对象创建的代码:

//简单工厂
class SimpleFactory {companion object {@JvmStaticfun create(path: String): IRuleConfigParser? {return if (path.endsWith("json", true)) {JsonRuleParser()} else if (path.endsWith("xml", true)) {XmlRuleParser()} else if (path.endsWith("yaml", true)) {YamlRuleParser()} else null}}
}

调用处:

fun loadConfig(path: String): Config? {val parser = SimpleFactory.create(path)val config = parser?.parser(path)return config
}

可以看到调用处代码非常简洁,创建代码都被封装到工厂类中了,开发中只要维护工厂代码即可。其实该例子创建的对象是可以复用的,那么还可以在工厂类中通过 map 缓存创建的对象,不必每次都创建新对象。同时 map 还可以取代 if-else 形式的代码:

//带缓存的简单工厂
class SimpleFactory {companion object {@JvmStaticprivate val cacheMap: HashMap<String, IRuleConfigParser> = hashMapOf("json" to JsonRuleParser(),"xml" to XmlRuleParser(),"yaml" to YamlRuleParser(),)@JvmStaticfun create(path: String): IRuleConfigParser? {val extension = getFileExtension(path)return cacheMap[extension]}@JvmStaticfun getFileExtension(filePath: String): String {//...解析文件名获取扩展名,比如rule.json,返回jsonreturn filePath.substringAfterLast('.', "")}}
}

简单工厂模式的问题是,如果需要扩展新的产品类,就需要修改工厂类的代码,违反了开闭原则,所以只适合改动不频繁的简单场景(设计原则没必要严格遵守,根据场景灵活使用才是目的)

这里的解析器创建只是简单的 new 了一个对象,如果解析器的创建流程变得复杂,那 create() 方法中的代码也会随之变得冗长,这种情况下可以把解析器复杂的创建逻辑进一步封装到各个工厂类中,这就成了工厂方法模式。

三、工厂方法(Factory Method)

工厂方法模式定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法让类的实例化延迟到子类中进行。这种方式的好处是,新增产品类时,只需要增加一个具体的产品类和对应的具体工厂类,而不需要修改原有的工厂接口和工厂类。

下面使用工厂方法封装解析器创建流程:

//封装每个解析器的创建过程
interface IRuleConfigParserFactory {fun create(): IRuleConfigParser
}//Json解析器创建
class JsonParserFactory : IRuleConfigParserFactory {override fun create(): IRuleConfigParser {val parser = JsonRuleParser()//parser.xxx = xxx//...return parser}
}//Xml解析器创建
class XmlParserFactory: IRuleConfigParserFactory {override fun create(): IRuleConfigParser = XmlRuleParser()
}//Yaml解析器创建
class YamlParserFactory: IRuleConfigParserFactory {override fun create(): IRuleConfigParser = YamlRuleParser()
}//这里其实还是简单工厂
class MethodFactory {companion object {@JvmStaticfun create(path: String): IRuleConfigParser? {var parserFactory: IRuleConfigParserFactory? = nullif (path.endsWith("json", true)) {parserFactory = JsonParserFactory()} else if (path.endsWith("xml", true)) {parserFactory = XmlParserFactory()} else if (path.endsWith("yaml", true)) {parserFactory = YamlParserFactory()}return parserFactory?.create()}}
}

外部调用:

fun loadConfig(path: String): Config? {val parser = MethodFactory.create(path)val config = parser?.parser(path)return config
}

可以看到复杂的解析器创建逻辑被隔离到具体的工厂创建类中了,又用简单工厂简化了调用代码。可以发现,简单工厂侧重对分支代码的封装,而工厂方法更侧重隔离对象创建的复杂代码,两者还可以组合使用。

工厂方法缺点是,如果工厂不只是生产一种类型的对象,或者说创建的对象会根据多个维度分类,那工厂方法的实现类将会非常多,从而难以维护。如上面的例子,解析器除了根据文件格式分类,还增加了文件大小的维度,这时候需要实现的类就有 3 x 2 = 6个:

SmallJsonParserFactory
SmallXmlParserFactory
SmallYamlParserFactory
BigJsonParserFactory
BigXmlParserFactory
BigYamParserFactory

可见创建对象维度的增加会导致工厂类爆增,针对上面场景,就可以使用抽象工厂,让一个工厂可以生产不同类型的对象。

四、抽象工厂(Abstract Factory)

抽象工厂模式使用抽象的接口来创建一系列相关或相互依赖的对象,而无需指定它们具体的类。这种方式主要用于创建一组相互依赖或关联的对象,而不需要指定它们具体的类。

以上面新增文件大小维度举例,抽象出代码如下:

//抽象工厂
interface IConfigParserFactory {fun createJsonFactory(): IRuleConfigParserfun createXmlFactory(): IRuleConfigParserfun createYamlFactory(): IRuleConfigParser
}//大文件解析器
class ConfigBigParser: IConfigParserFactory {override fun createJsonFactory(): IRuleConfigParser {//再这里创建不同维度的产品类return JsonRuleParser()}override fun createXmlFactory(): IRuleConfigParser {return XmlRuleParser()}override fun createYamlFactory(): IRuleConfigParser {return YamlRuleParser()}
}//小文件解析器
class ConfigSmallParser: IConfigParserFactory {override fun createJsonFactory(): IRuleConfigParser {//..省略return JsonRuleParser()}override fun createXmlFactory(): IRuleConfigParser {//..省略return XmlRuleParser()}override fun createYamlFactory(): IRuleConfigParser {//..省略return YamlRuleParser()}
}

调用处代码:

fun loadConfig3(path: String): Config? {//可根据具体业务,通过抽象工厂创建不同的产品类,无须关心实现类val parser1 = ConfigBigParser()val parser2 = ConfigSmallParser()parser1.createJsonFactory()parser1.createXmlFactory()parser1.createYamlFactory()parser2.createJsonFactory()parser2.createXmlFactory()parser2.createYamlFactory()
}

抽象工厂模式是工厂方法模式的升级版本,在有多个业务品种、业务分类时,通过抽象工厂模式产生需要的对象是一种非常好的解决方式。

总结

工厂模式是将对象创建的过程封装,创建对象的复杂代码被隔离到每个工厂内部消化,从而实现对象的创建与使用分离。不同工厂模式适用于不同的场景,选择哪种模式取决于具体的需求和场景。

http://www.lryc.cn/news/431601.html

相关文章:

  • 使用Cskin时候 遇到按钮有默认阴影问题解决
  • 121.rk3399 uboot(2017.09) 源码分析1(2024-09-05)
  • 【图论】虚树 - 模板总结
  • [C#学习笔记]注释
  • c# checkbox的text文字放到右边
  • 【node.js】基础之修改文件
  • Notepad++回车不自动补全
  • CSS线性渐变拼接,一个完整的渐变容器(div),要拆分成多个渐变容器(div),并且保持渐变效果一致
  • 【60天备战软考高级系统架构设计师——第十天:软件设计与架构综合练习】
  • 2024.8.15(python管理mysql、Mycat实现读写分离)
  • CMU 10423 Generative AI:lec2
  • 恋爱相亲交友系统源码原生源码可二次开发APP 小程序 H5,web全适配
  • OceanBase 4.x 存储引擎解析:如何让历史库场景成本降低50%+
  • js 如何写构造函数 ,构造函数和普通函数有什么区别
  • MySQL-进阶篇-锁(全局锁、表级锁、行级锁)
  • c++懒汉式单例模式(Singleton)多种实现方式及最优比较
  • Gartner《2024中国安全技术成熟度曲线》AI安全助手代表性产品:开发者安全助手D10
  • 奇安信椒图--服务器安全管理系统(云锁)
  • pointer-events,添加水印的一个小小点
  • 微服务--认识微服务
  • 【docker】docker 镜像仓库的管理
  • 第L2周:机器学习-线性回归
  • SpringMVC拦截器深度解析与实战
  • 直线上最多的点数
  • 经济管理专业数据库介绍
  • 【C++ Primer Plus习题】11.1
  • [数据库][oracle]ORACLE EXP/IMP的使用详解
  • 中国各银行流动性比例数据(2000-2022年)
  • MACOS安装配置前端开发环境
  • Docker 配置国内镜像源