| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> Java知识库 -> 设计模式之工厂方法模式:如何解决生成对象时的不确定性? -> 正文阅读 |
|
[Java知识库]设计模式之工厂方法模式:如何解决生成对象时的不确定性? |
一、模式原理分析在上一讲中,我们介绍了工厂模式中的抽象工厂模式,为便于你更好地理解,我们还通过家具厂的实例讲解了抽象工厂的使用步骤,并结合 Spring Framework 框架中的 BeanFactory 说明了寻找正确抽象的重要性。 今天我们接着来讲解另外一个工厂模式:工厂方法模式(Factory Method Pattern)。 工厂方法模式就是我们俗称的工厂模式,和抽象工厂模式很类似,但工厂方法模式因为只围绕着一类接口来进行对象的创建与使用,使用场景更简单和单一,在实际的项目中使用频率反而比抽象工厂模式更高。 工厂方法模式的原始定义是:定义一个创建对象的接口,但让实现这个接口的类来决定实例化哪个类。 工厂方法模式的目的很简单,就是封装对象创建的过程,提升创建对象方法的可复用性。 我们直接来看看工厂方法模式的 UML 图: ? 从图中可以看出,工厂方法模式包含三个关键角色:
其中,核心工厂通常作为父类负责定义创建对象的抽象接口以及使用哪些具体产品,具体产品可以是一个具体的类,也可以是一个具体工厂类,负责生成具体的对象实例。于是,工厂方法模式便将对象的实例化操作延迟到了具体产品子类中去完成。 不同于抽象工厂模式,工厂方法模式侧重于直接对具体产品的实现进行封装和调用,通过统一的接口定义来约束程序的对外行为。换句话说,用户通过使用核心工厂来获得具体实例对象,再通过对象的统一接口来使用对象功能。 工厂方法模式对应 UML 图的代码实现如下:
这段代码实现很简单,通过定义一个通用的接口 IProduct,实现 use 的方法,并使用 ProductFactory 工厂通过产品名称来创建具体子类。 在前面的《15 | 分离原则:如何将复杂问题拆分成小问题?》这一讲,我们介绍过一个视角:使用与创建分离。我们知道了使用与创建分离的好处在于能够提升组件的复用性,同时保证对象在同一个逻辑层级里,能够方便阅读与维护。 但你发现没,实际上使用工厂方法模式就能很好地实现分离原则。在工厂方法模式中,核心的工厂 ProductFactory 类不会负责所有产品的创建,只是负责实现通用逻辑,具体的实例创建工作都是交给具体工厂去做的,同时子类需要实现一个公共的接口来对外提供统一的功能,这使得工厂方法模式可以允许程序在不修改工厂角色的情况下引入新的产品实现。 那么,工厂方法模式封装了哪些变化呢?主要有以下三个。
总体来说,工厂方法模式是围绕着特定的抽象产品(一般是接口)来封装对象的创建过程,客户端只需要通过工厂类来创建对象并使用特定接口的功能。 二、使用场景分析一般情况下,工厂方法模式有以下几个使用场景。
为了帮助你更好地理解使用场景的本质特征,这里我们通过一段经典的源码实现——MyBatis 实现的 Log 日志功能——来学习。代码如下:
这段代码的实现很简单,却充分体现了工厂方法模式使用场景的本质:尽可能地封装对象创建过程中所遇见的所有可能变化。 这里 LogFactory 的职责就是核心工厂的创建职责,所需要创建的具体产品就是实现 Log 这个接口的特定实现,比如,Slf4j、Log4J 等。Log 接口代码如下所示:
而具体的产品实现就是通过以下的类去实现的:
如果你看过这些具体类的代码实现,就会发现各自的代码风格可能完全不同,但最终实现的日志功能却是一样的。其中,Slf4jImpl 甚至还为不同的 Slf4j 版本 API 接口做了兼容性处理,如果想要扩展一个新的日志实现,那么新增一个实现类并在核心工厂类里加入你的调用代码即可。 你发现没,这里的关键其实是 Log 这个接口,这个接口设计得非常好,也就是抽象产品设计得特别好,不仅满足接口隔离原则,而且还是找到了正确抽象的典型代表。每一个操作几乎都是日志相关的原子操作,即便具体类的实现不同,但只要使用 LogFactory 就能获得满足要求的日志功能。 三、为什么要用工厂方法模式?分析完工厂方法模式的原理和使用场景后,我们再来说说使用工厂方法模式的原因,主要有以下三个。 第一个,为了把对象的创建和使用过程分开,降低代码耦合性。?这是使用工厂方法模式最直接的理由之一。在实际的软件开发中,你可能更喜欢使用 new 来创建对象,同时紧接着便开始使用新创建的对象,这看上去并没有什么问题,但是随着创建对象数量的增多,你会发现,当你想要重构、修改已有的对象属性和方法时,你几乎不敢轻易修改,因为你早已记不清哪些对象在哪里被创建和使用,以及跟哪些对象发生了关联和交互。而使用工厂方法模式,就能很好地避免这个问题,创建的过程始终在工厂内部管理,只要对外使用的方法不发生变化,那么就不会对创建对象造成影响。 第二个,减少重复代码。?对于要写代码的程序员或架构师来说,面对成千上万相同的数据对象进行增删改查时,如果每次都使用 new 来创建对象的话,那么 80% 的时间都会浪费在同样属性的 get 与 set 上。这时要是使用的对象之间还有相互引用的话(A 引用 B,B 又引用 C……),重复的代码就会剧增。而对于多个相同对象的构建过程,除了使用建造者模式以外,还可以使用工厂方法模式来避免出现过多的重复代码,将相同的创建规则统一放在一起。 第三个,统一管理创建对象的不同实现逻辑。?比如,当一个业务对象发生业务逻辑变化时,使用工厂方法模式后,你不需要找到所有创建对象的地方去修改,而只需要在工厂里修改即可。即便这时你想要扩展对象为新的子类,也不需要把所有调用父类的地方都改成子类,只需要在工厂中修改其生产的对象为新的子类。同时,还隐藏了具体的创建过程,减少了使用者误用逻辑而导致未知错误出现的概率 四、收益与损失使用工厂方法模式主要有以下几个优点。
同样,除了以上优点以外,工厂方法模式也有一些缺点。
五、总结工厂方法模式的原理和使用都很简单,并且还可以很方便地通过子类进行定制,因此,在软件开发的早期,开发人员会很容易选择和使用工厂方法模式。另外,随着时间的推移,还可以将工厂方法模式演变为使用抽象工厂模式,进而极大地提升了程序的可扩展性。 不过在我看来,如果对象的属性数量并不多,并且创建过程也不复杂的话,那么用不着使用工厂方法模式来创建对象,毕竟工厂方法模式强调使用继承来实现对象的创建,会引入继承相关的副作用。 这里尤其要注意的是,工厂方法模式和抽象工厂模式虽然都用于创建对象,但是两者的侧重点是完全不同的。工厂方法模式侧重于继承的连续性,而抽象工厂模式侧重于组合的扩展性,这就导致了工厂方法模式会更多去关注是否满足里氏替换原则,而抽象工厂模式很多时候是要寻找到更好的抽象产品,这期间很有可能是会违反里氏替换原则的。 六、课后思考在文中 LogFactory 的代码实现里,如果不使用静态加载来实现具体产品的初始化的话,要想实现接入更多日志组件的话,该如何实现呢? |
|
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/24 12:00:43- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |