《重构改善既有代码的设计》之重构列表--处理概括关系(三)

2023-12-16 14:48

本文主要是介绍《重构改善既有代码的设计》之重构列表--处理概括关系(三),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

九、Collapse Hierarchy(折叠继承体系)

超类和子类之间无太大区别。

将它们合为一体。

动机

如果你曾经编写过继承体系,就会知道,继承体系很容易变得过分复杂。所谓重构继承体系,往往是将函数和字段在体系中上下移到。完成这些动作后,你狠可能发现某个子类并未带来该有的价值,因此需要把超类和子类合并起来。

做法

1、选择你想移除的类:是超类还是子类?

2、使用Pull Up Field 和 Pull Up Method,或者Push Down FieldPush Down Method,把想要移除的类的所有行为和数据搬移到另一个类。

3、每次移动后,编译并测试。

4、调整即将被移除的那个类的所有引用点,令它们改而引用合并后留下的那个类。

。这个动作将会影响变量的声明、参数的类型以及构造函数。

5、移除我们的目标:此时的它应该已经成为一个空类。

6、编译,测试。

十、Form Template Method(塑造模板函数)

你有一些类,其中相应的某些函数以相同顺序执行类似的操作,但各个操作的细节上有所不同。

将这些操作分别放进独立函数中,并保持它们都有相同的签名,于是原函数也就变得相同了。然后将原函数上移至超类。

动机

继承是避免重复行为的一个强大工具。无论何时,只要你看见两个子类中有类似的函数,就可以把它们提升到超类。但是如果这些函数并不完全相同该怎么办?我们仍有必要尽量避免重复,但又必须保持这些函数之间的实质差异。

常见的一种情况是:两个函数以相同顺序执行大致相近的操作,但是各个操作不完全相同。这种情况下我们可以将执行操作的序列移至超类,并借助多态保证各操作仍得以保持差异性。这样的函被称为Template Method(模板函数)

做法

1、在各个子类中分解目标函数,使分解后的各个函数要不完全相同,要不完全不同。

2、运用Pull Up Method将各子类内完全相同的函数上移至超类。

3、对于那些(剩余的、存在于各个子类内的)完全不同的函数,实施Rename Method,使所有的这些函数的签名完全不同。

这将使得原函数变为完全相同,因为它们都执行统一一组函数调用;但各子类会以不同方式相应这些调用。

4、修改上述所有签名后,编译并测试。

5、运用Pull Up Method将所有原函数逐一上移至超类。在超类中将那些代表各个不同操作的函数定义为抽象函数。

6、编译,测试。

7、移除其他子类中的原函数,每删除一个,编译并测试。

十一、Replace Inheritance with Delegation(以委托取代继承)

某个子类只使用超类接口中的一部分,或是根本不需要继承而来的数据。

在子类中新建字段用以保存超类;调整子类函数,令它改而委托超类;然后去掉两者之间的继承关系。

动机

继承是个好东西,但有时候它并不是你要的。你常常会遇到这样的情况:一开始继承了一个类,随后发现超类中的许多操作并不真正适用于子类。这种情况下,你所拥有的接口并未真正反映出子类的功能。或者,你可能发现你从超类中继承了一大堆子类并不需要的数据,抑或你发现超类中的某些protected函数对子类并没有什么意义。

你可以选择容忍,并接受传统说法:子类可以只使用超类功能的一部分。但这样做的结果是:代码传达的信息与你的意图南辕北辙---这是一种混淆,你应该将它去除。

如果以委托取代继承,你可以更清楚地表明:你只需要受托类的一部分功能。接口中的那一部分应该被使用,哪一部分应该被忽略,完全由你主导控制。这样做的成本则是需要额外写出委托函数,但这些函数都非常简单,极少可能出错。

做法

1、在子类中新建一个字段,使其引用超类的一个实例,并将它初始化为this.

2、修改子类内的所有函数,让它们不再使用超类,转而使用上述那个受托字段。每次修改后,编译并测试。

你不能这样修改子类中通过super调用的超类函数的代码,否则它们会陷入无限递归。这种函数只有在继承体系被打破后才能修改。

3、去除两个类之间的继承关系,新建一个受托类的对象赋给受托字段。

4、针对客户端所用的每一个超类函数,为它添加一个简单的受托函数。

5、编译,测试。

十二、Replace Delegation with Inheritance(以继承取代委托)

你在两个类之间使用委托关系,并经常为整个接口编写许多简单的委托函数。

让委托类继承受托类。

动机

本重构与Replace Inheritance with Delegation恰恰相反。如果你发现自己需要使用受托类中的所有函数,并且费了很大力气编写所有极简的委托函数,本重构可以帮助你轻松回头使用继承。

两条告诫需牢记于心。首先,如果你并没有使用受托类的所有函数,那么就不应该使用Replace Delegation with Inheritance,因为子类应该总是遵循超类的接口。如果过多的委托函数让你烦心,你有别的选择:你可以通过Remove Middle Man容乃公客户端自己调用受托函数,也可以使用Extract Superclass将两个类接口相同的部分提炼到超类中,然后让两个类都继承这个新的超类;你还可以用类似的手法使用Extract Interface

另一种需要当心的情况是:受托对象被不止一个其他对象共享,而且受托对象是可变的。在这种情况下,你就不能将委托关系替换为继承关系,因为这样就无法再共享数据了。数据共享是必须由委托关系承担的一种责任,你无法把它转给继承关系。如果受托对象是可变的,数据共享就不成问题,因为你大可放心的复制对象,谁都不会知道。

做法

1、让委托端成为受托端的一个子类。

2、编译。

此时,某些函数可能会发生冲突:它们可能有相同的名称,但在返回类型、异常指定或可见程度方面有所差异。你可以使用Rename Method解决此类问题。、

3、将受托字段设为该字段所处对象本身。

4、去掉简单的委托函数。

5、编译并测试。

6、将所有其他涉及委托关系的代码,改为调用对象自身。

7、移除受托字段。

这篇关于《重构改善既有代码的设计》之重构列表--处理概括关系(三)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/500856

相关文章

Java堆转储文件之1.6G大文件处理完整指南

《Java堆转储文件之1.6G大文件处理完整指南》堆转储文件是优化、分析内存消耗的重要工具,:本文主要介绍Java堆转储文件之1.6G大文件处理的相关资料,文中通过代码介绍的非常详细,需要的朋友可... 目录前言文件为什么这么大?如何处理这个文件?分析文件内容(推荐)删除文件(如果不需要)查看错误来源如何避

MySQL进行数据库审计的详细步骤和示例代码

《MySQL进行数据库审计的详细步骤和示例代码》数据库审计通过触发器、内置功能及第三方工具记录和监控数据库活动,确保安全、完整与合规,Java代码实现自动化日志记录,整合分析系统提升监控效率,本文给大... 目录一、数据库审计的基本概念二、使用触发器进行数据库审计1. 创建审计表2. 创建触发器三、Java

使用Python构建一个高效的日志处理系统

《使用Python构建一个高效的日志处理系统》这篇文章主要为大家详细讲解了如何使用Python开发一个专业的日志分析工具,能够自动化处理、分析和可视化各类日志文件,大幅提升运维效率,需要的可以了解下... 目录环境准备工具功能概述完整代码实现代码深度解析1. 类设计与初始化2. 日志解析核心逻辑3. 文件处

Java docx4j高效处理Word文档的实战指南

《Javadocx4j高效处理Word文档的实战指南》对于需要在Java应用程序中生成、修改或处理Word文档的开发者来说,docx4j是一个强大而专业的选择,下面我们就来看看docx4j的具体使用... 目录引言一、环境准备与基础配置1.1 Maven依赖配置1.2 初始化测试类二、增强版文档操作示例2.

MyBatis-Plus通用中等、大量数据分批查询和处理方法

《MyBatis-Plus通用中等、大量数据分批查询和处理方法》文章介绍MyBatis-Plus分页查询处理,通过函数式接口与Lambda表达式实现通用逻辑,方法抽象但功能强大,建议扩展分批处理及流式... 目录函数式接口获取分页数据接口数据处理接口通用逻辑工具类使用方法简单查询自定义查询方法总结函数式接口

SpringBoot结合Docker进行容器化处理指南

《SpringBoot结合Docker进行容器化处理指南》在当今快速发展的软件工程领域,SpringBoot和Docker已经成为现代Java开发者的必备工具,本文将深入讲解如何将一个SpringBo... 目录前言一、为什么选择 Spring Bootjavascript + docker1. 快速部署与

Python中将嵌套列表扁平化的多种实现方法

《Python中将嵌套列表扁平化的多种实现方法》在Python编程中,我们常常会遇到需要将嵌套列表(即列表中包含列表)转换为一个一维的扁平列表的需求,本文将给大家介绍了多种实现这一目标的方法,需要的朋... 目录python中将嵌套列表扁平化的方法技术背景实现步骤1. 使用嵌套列表推导式2. 使用itert

Python使用vllm处理多模态数据的预处理技巧

《Python使用vllm处理多模态数据的预处理技巧》本文深入探讨了在Python环境下使用vLLM处理多模态数据的预处理技巧,我们将从基础概念出发,详细讲解文本、图像、音频等多模态数据的预处理方法,... 目录1. 背景介绍1.1 目的和范围1.2 预期读者1.3 文档结构概述1.4 术语表1.4.1 核

Spring Boot @RestControllerAdvice全局异常处理最佳实践

《SpringBoot@RestControllerAdvice全局异常处理最佳实践》本文详解SpringBoot中通过@RestControllerAdvice实现全局异常处理,强调代码复用、统... 目录前言一、为什么要使用全局异常处理?二、核心注解解析1. @RestControllerAdvice2

java中新生代和老生代的关系说明

《java中新生代和老生代的关系说明》:本文主要介绍java中新生代和老生代的关系说明,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、内存区域划分新生代老年代二、对象生命周期与晋升流程三、新生代与老年代的协作机制1. 跨代引用处理2. 动态年龄判定3. 空间分