设计模式之死磕工厂方法模式(原创)

简介: 在 设计模式之工厂模式 中,我们提到过工厂模式仔细区分的话分为三种,分别是简单工厂模式、工厂方法模式以及抽象工厂模式。在上面已经介绍完毕了工厂模式(也就是简单工厂模式)。

在 设计模式之工厂模式 中,我们提到过工厂模式仔细区分的话分为三种,分别是简单工厂模式、工厂方法模式以及抽象工厂模式。在上面已经介绍完毕了工厂模式(也就是简单工厂模式)。本篇文章主要学习的是工厂模式的第二种,工厂方法模式。

注:本文是基于 设计模式之工厂模式 的文章之上进行编码以及项目说明

首先回顾下工厂模式的基本概念:我们在创建对象时不会对客户端直接暴露创建逻辑,而是 通过使用一个共同的接口根据不同的条件来指向具体想要创建的对象。

通过一个共同的接口根据不同的条件来指向想要创建的对象,这个切入点肯定没错,在上一篇文章也讲到,我们通过使用工厂模式的优点在于一个调用者想创建一个对象,只要知道其名称(也就是不同的标签)就可以在工厂获取具体的对象;其次,在这种设计模式下会屏蔽产品的具体实现,调用者只关心产品的接口、无需关心内部实现。

但是,这样也会带来一个问题,如果我想增加一个(也就是具体的对象),那就需要扩展工厂类(也就是首先要增加不同的标签,然后增加不同标签所对应的对象)。如果这样操作的话,就违背了“开闭”原则。那么,什么是开闭原则?

在 设计模式概念与简介 这篇文章中简单介绍了开闭原则,那么这里对开闭原则做更加详细的分析。

开闭原则(OCP)是面向对象设计中“可复用设计”的基石,是面向对象设计中最重要的原则之一,其它很多的设计原则都是实现开闭原则的一种手段。开、闭的字面理解就是对于扩展是开放的,对于修改是关闭的,这意味着模块的行为是可以扩展的。当应用的需求改变时,我们可以对模块进行扩展,使其具有满足那些改变的新行为。更通俗一点,也就是:软件系统中包含的各种组件,例如模块(Modules)、类(Classes)以及功能(Functions)等等,应该在不修改现有代码的基础上,引入新功能。

既然开闭原则是如此的重要,那么开发者应该如何实现开闭原则

A:抽象约束 

抽象是对一组事物的通用描述,没有具体的实现,也就表示它可以有非常多的可能性,可以跟随需求的变化而变化。因此,通过接口或抽象类可以约束一组可能变化的行为,并且能够实现对扩展开放,其包含三层含义:

通过接口或抽象类约束扩散,对扩展进行边界限定,不允许出现在接口或抽象类中不存在的public方法。

参数类型,引用对象尽量使用接口或抽象类,而不是实现类,这主要是实现里氏替换原则的一个要求

抽象层尽量保持稳定,一旦确定就不要修改

B:元数据(metadata)控件模块行为 

编程是一个很苦很累的活,那怎么才能减轻压力呢?答案是尽量使用元数据来控制程序的行为,减少重复开发。什么是元数据?用来描述环境和数据的数据,通俗的说就是配置参数,参数可以从文件中获得,也可以从数据库中获得。

C:制定项目章程 

在一个团队中,建立项目章程是非常重要的,因为章程是所有人员都必须遵守的约定,对项目来说,约定优于配置。这比通过接口或抽象类进行约束效率更高,而扩展性一点也没有减少。

D:封装变化 

对变化封装包含两层含义: 

(1)将相同的变化封装到一个接口或抽象类中 

(2)将不同的变化封装到不同的接口或抽象类中,不应该有两个不同的变化出现在同一个接口或抽象类中。 

封装变化,也就是受保护的变化,找出预计有变化或不稳定的点,我们为这些变化点创建稳定的接口。

开闭原则的具体实现与相互关系:

开闭原则被称作面向对象设计的终极目标。因此,针对开闭原则的实现方法,一直都有面向对象设计的大师费尽心机去研究开闭原则的实现方式。但是在平时的开发中我们已经直接或者间接的已经接触到了开闭原则的设计理念。比如,设计模式概念中提到的里氏代换原则、依赖倒转原则、接口隔离原则 以及常用的接口、抽象类等等,都可以看作是开闭原则的具体实现方法。

那么在回到上面的问题,当需求发生变化的时候,简单工厂模式下进行修改操作的话是违背开闭原则的(当然你说这样也无所谓,这个功能怎么实现我不管、反正可以用就行),那么如何解决上面的问题?

比较高效和容易理解的方式是,在定义一个抽象的英雄工厂类型的基类,让子类自己去实现该基类(也就是工厂与实例对象互相对应)。

首先还是跟上一篇文章一样,基本代码不变:

img_3f4488e5f296bb9855841faa07e73377.png
英雄规范

接着是已持有的三个英雄:

img_3552208c141c067c5fe80a2ef9d65340.png
Ashe
img_ab5703d856b7807b352a62724b07d0f5.png
MasterYi
img_eaeefe9f5f955a57066ca2855172b155.png
Timor

上面的代码和简单工厂模式下的代码都是一样的,针对上面的问题,我们提到可以定义一个抽象的英雄工厂类型的基类

img_104f16a2a165647fac80729cc79bb8a9.png
定义基类

其中,这里基类的抽象方法,返回的是具体的英雄参数类型,那么通过子类就可以进行具体的操作(将对象返回出去即可)三个具体的英雄对应三种具体的工厂

img_be7501c623c04761f8c485a374a985c4.png
射手工厂
img_15f05cb99b9b5ab7b44b20cdc01bcc21.png
法师工厂
img_ff9b6f3abbca5feb79470f8b072aa247.png
战士工厂

定义完三个工厂以后,我们就可以测试使用了:

img_313c67e88bb1b5e57386181ce18eb5ff.png
测试工厂方法模式

可能会说,这两种模式有什么区别?这里先上一下两种工厂模式下的测试类比较:

img_c4de1b17cbd7eb23ce3907979d6f6cd8.png
两种模式测试比较

其中,红色箭头的是简单工厂模式(这种模式下将所有的标签和对象全部统一在这里进行管理使用)

蓝色箭头代表的是工厂方法模式,在这种模式下,各个工厂内对象依据工厂类型不同进行创建。

简单工厂模式和工厂方法模式的比较:

简单工厂模式是专门定义一个类(工厂类)来负责创建其他类的实例,被创建的实例通常都具有共同的父类。它又称为静态工厂方法模式。本质是由一个工厂类根据传入的参数动态决定创建那一个产品类(这些产品类继承自一个父类或接口)的实例对象。在这种模式下工厂类是整个模式的关键,它包含必要的逻辑判断能够根据外界给定的信息决定究竟应该创建那个具体类的对象。

工厂方法模式是粒度很小的设计模式,因为模式的表现是一个抽象的方法。提前定义用于创建对象的接口让子类决定实例化具体的某一个类,即在工厂和产品中间增加一个接口(或者抽象类),工厂不再负责产品的创建,由接口针对不同条件返回具体的实例,由具体类实例去实现。工厂方法模式是简单工厂模式的衍生解决了之前简单工厂模式下带来的问题。完全实现了开闭原则。工厂方法模式是对简单工厂模式进行了抽象。有一个抽象的Factory类(接口或者抽象)这个类不在负责具体的产品生产(也就是new 对象),而是只指定规范,具体的实现由子类完成。在这种模式下,工厂类和产品往往可以互相对应。即一个抽象工厂对应一个抽象产品,一个具体的工厂对应一个具体的产品,这个具体的工厂就负责生产对象的产品(也就是上面的蓝色箭头)

简单工厂模式和工厂方法模式的优缺点:

简单工厂模式:

优点:工厂类含有必要的逻辑判断,可以依据不同的标签创建不同的对象,实现了对责任的分割,耦合性较低。有利于整个软件体系结构的优化

缺点:拓展性相对较低(因此出现了工厂方法模式)

工厂方法模式:

优点:这种模式是为了克服简单工厂模式下的缺点(主要是开闭原则),这种模式下每个具体的工厂类只完成单一任务,代码简洁,拓展性强

缺点:不易于维护,修改产品对象也要修改对应的工厂类(修改多个产品就要修改多个工厂)

简单工厂模式和工厂方法模式的适用范围:

简单工厂模式:工厂类负责创建的对象比较少,客户只知道传入了工厂类的参数,对于创建的逻辑不关心。且使用一个共同的接口根据不同的条件来指向具体想要创建的对象可以使用简单工厂模式

工厂方法模式:当一个类不知道它所必须创建对象的类或者一个类希望由子类来指定它所创建的对象时;当类将创建的需的职责委托给帮助类中的某一个,并且希望得到指定帮助类的信息,可以使用工厂方法模式

参考资料:百度百科

如果这篇文章对你有帮助,希望各位看官留下宝贵的star,谢谢。

Ps:著作权归作者所有,转载请注明作者, 商业转载请联系作者获得授权,非商业转载请注明出处(开头或结尾请添加转载出处,添加原文url地址),文章请勿滥用,也希望大家尊重笔者的劳动成果。

相关文章
|
6天前
|
设计模式 数据库连接 PHP
PHP中的设计模式:提升代码的可维护性与扩展性在软件开发过程中,设计模式是开发者们经常用到的工具之一。它们提供了经过验证的解决方案,可以帮助我们解决常见的软件设计问题。本文将介绍PHP中常用的设计模式,以及如何利用这些模式来提高代码的可维护性和扩展性。我们将从基础的设计模式入手,逐步深入到更复杂的应用场景。通过实际案例分析,读者可以更好地理解如何在PHP开发中应用这些设计模式,从而写出更加高效、灵活和易于维护的代码。
本文探讨了PHP中常用的设计模式及其在实际项目中的应用。内容涵盖设计模式的基本概念、分类和具体使用场景,重点介绍了单例模式、工厂模式和观察者模式等常见模式。通过具体的代码示例,展示了如何在PHP项目中有效利用设计模式来提升代码的可维护性和扩展性。文章还讨论了设计模式的选择原则和注意事项,帮助开发者在不同情境下做出最佳决策。
|
21天前
|
设计模式 算法 安全
设计模式——模板模式
模板方法模式、钩子方法、Spring源码AbstractApplicationContext类用到的模板方法
设计模式——模板模式
|
13天前
|
设计模式 数据库连接 PHP
PHP中的设计模式:如何提高代码的可维护性与扩展性在软件开发领域,PHP 是一种广泛使用的服务器端脚本语言。随着项目规模的扩大和复杂性的增加,保持代码的可维护性和可扩展性变得越来越重要。本文将探讨 PHP 中的设计模式,并通过实例展示如何应用这些模式来提高代码质量。
设计模式是经过验证的解决软件设计问题的方法。它们不是具体的代码,而是一种编码和设计经验的总结。在PHP开发中,合理地使用设计模式可以显著提高代码的可维护性、复用性和扩展性。本文将介绍几种常见的设计模式,包括单例模式、工厂模式和观察者模式,并通过具体的例子展示如何在PHP项目中应用这些模式。
|
11天前
|
设计模式 Java Spring
spring源码设计模式分析-代理设计模式(二)
spring源码设计模式分析-代理设计模式(二)
|
8天前
|
设计模式
设计模式-工厂模式 Factory Pattern(简单工厂、工厂方法、抽象工厂)
这篇文章详细解释了工厂模式,包括简单工厂、工厂方法和抽象工厂三种类型。每种模式都通过代码示例展示了其应用场景和实现方法,并比较了它们之间的差异。简单工厂模式通过一个工厂类来创建各种产品;工厂方法模式通过定义一个创建对象的接口,由子类决定实例化哪个类;抽象工厂模式提供一个创建相关或依赖对象家族的接口,而不需要明确指定具体类。
设计模式-工厂模式 Factory Pattern(简单工厂、工厂方法、抽象工厂)
|
9天前
|
设计模式 Java
Java设计模式-工厂方法模式(4)
Java设计模式-工厂方法模式(4)
|
2月前
|
设计模式
设计模式-单一职责模式
设计模式-单一职责模式
|
2月前
|
设计模式 XML 存储
【二】设计模式~~~创建型模式~~~工厂方法模式(Java)
文章详细介绍了工厂方法模式(Factory Method Pattern),这是一种创建型设计模式,用于将对象的创建过程委托给多个工厂子类中的某一个,以实现对象创建的封装和扩展性。文章通过日志记录器的实例,展示了工厂方法模式的结构、角色、时序图、代码实现、优点、缺点以及适用环境,并探讨了如何通过配置文件和Java反射机制实现工厂的动态创建。
【二】设计模式~~~创建型模式~~~工厂方法模式(Java)
|
2月前
|
设计模式 XML Java
【一】设计模式~~~创建型模式~~~简单工厂模式(Java)
文章详细介绍了简单工厂模式(Simple Factory Pattern),这是一种创建型设计模式,用于根据输入参数的不同返回不同类的实例,而客户端不需要知道具体类名。文章通过图表类的实例,展示了简单工厂模式的结构、时序图、代码实现、优缺点以及适用环境,并提供了Java代码示例和扩展应用,如通过配置文件读取参数来实现对象的创建。
【一】设计模式~~~创建型模式~~~简单工厂模式(Java)
|
2月前
|
设计模式 uml C语言
设计模式----------工厂模式之简单工厂模式(创建型)
这篇文章详细介绍了简单工厂模式,包括其定义、应用场景、UML类图、通用代码实现、运行结果、实际应用例子,以及如何通过反射机制实现对象创建,从而提高代码的扩展性和维护性。
设计模式----------工厂模式之简单工厂模式(创建型)