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

2023-12-16 14:48

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

有一批重构手法专门用来处理概括关系(既继承关系)。

一、Pull Up Field(字段上移)

两个子类拥有相同的字段。

将该字段移至超类中。

动机

如果各子类是分别开发的,或者是在重构过程中组合起来的,你常会发现他们拥有重复特性,特别是字段更容易重复,这样的字段有时拥有相似的名字,但也并非绝对如此。判断若干字段是否重复,唯一的办法是观察函数如果使用它们。如果它们被使用的方式相似,你就可以将它们归纳到超类中。

本项重构从两方面减少重复:首先它去除了重复的数据声明;其次它使你可以将使用该字段的行为从子类一直超类,从而去除重复行为。

做法

1、针对待提升之字段,检查它们的所有被引用点,确认它们以同样的方式被使用。

2、如果这些字段的名称不同,先将它们改名,使每一个名称都和你想为超类字段取的名称相同。

3、编译并测试。

4、在超类中新建一个字段。

5、移除子类中的字段。

6、编译,测试。

7、考虑对超类的新建字段使用Self Encapsulate Field

二、Pull Up Method(函数上移)

有些函数,在各个子类中产品完全相同的结果。

将该函数移至超类。

动机

避免行为重复是很重要的。尽管重复的两个函数也可以很好的工作,但重复自身只会成为错误的滋生地,此外别无价值。无论何时,只有系统之内出现重复,你就会面临“修改其中一个却未能修改另一个”的风险。通常,找出重复也有一定的困难。

如果某个函数在各子类中的函数体都相同(它们很可能是通过复制粘贴得到的),这就是最显而易见的Pull Up Method适用场合。当然,情况并不总是如此明显。你也可以只管放心重构,再看看测试程序会不会发牢骚,但这就需要对你的测试有充分的信心。我发现观察这些可能重复的函数之间的差异往往大有收获:它们经常会向我们展示那些我忘记测试的行为。

Pull Up Method常常紧随其他重构而被使用。也许你能找出若干个身处不同子类内的函数,而它们又可以通过某种形式的参数调整成为相同的函数。这时候,最简单的办法就是首先分别调整这些函数的参数,然后再将它们概括到超类中。当然,如果你足够自信,也可以一次完成这两个步骤。

有一种特殊情况也需要使用Pull Up  Method:子类的函数覆写了超类的函数,但却仍然做相同的工作。

Pull Up Method过程中最麻烦的一点是:被提升的函数可能会引用只出现于子类而不出现于超类的特性。如果被引用的是个函数,你可以将该函数也一同提升到超类中,或者在超类中建立一个抽象函数。在此过程中,你可能需要修改某个函数的签名,或建立一个委托函数。

如果两个函数相似但不相同,你或许可以先借助Form Template Method构造出相同的函数,然后再提升它们。

做法

1、检查待提升函数,确定它们是完全一致的。

如果这些函数看上去做了相同的事,但并非完全一致,可使用Substitute Algorithm 让它们变得完全一致。

2、如果待提升函数的签名不同,将那些签名都修改为你想要在超类中使用的签名。

3、在超类中新建一个函数,将某一个待提升的函数的代码复制到其中,做适当的调整,然后编译。

如果你使用的是一种强类型语言,而待提升函数又调用了一个只出现于子类而未出现于超类的函数,你可以在超类中为被调用函数声明一个抽象函数。

如果待提升函数使用了子类的一个字段,你可以使用Pull Up Field将该字段提升到超类中;或者也可以先使用Self Encapsulate Field,然后在超类中把取值函数声明为抽象函数。

4、移除一个待提升子类函数。

5、编译、测试。

6、逐一移除待提升的子类函数,直到只剩下超类中的函数为止。每次移除后都需要测试。

7、观察该函数的调用者,看看是否可以改为使用超类类型的对象。

三、Pull Up Constructor Body(构造函数本体上移)

你在各个子类中拥有一些构造函数,它们的本体几乎完全一致。

在超类中新建一个构造函数,并在子类构造函数中调用它。

动机

构造函数是很奇妙的东西。它们不会普通的函数,使用它们比使用普通函数受到更多的限制。

如果你看到各个子类的函数有共同的行为,第一个念头就是将共同行为提炼到一个独立函数中,然后将这个函数提升到超类。对构造函数而言,它们彼此的共同行为往往就是“对象的建构”。这时候你需要在超类中提供一个构造函数,然后让子类都来调用它。很多时候,子类构造函数的唯一动作就是调用超类构造函数。这里不能运用Pull Up Method ,因为你无法在子类中继承超类构造函数。

如果重构过程过于复杂,你可以先考虑使用Replace Constructor with Factory Method

做法

1、在超类中定义一个构造函数。

2、将子类构造函数中的共同代码搬移到超类构造函数中。

被搬移的可能是子类构造函数的全部内容。

首先设法将共同代码搬移到子类构造函数中,然后再复制到超类构造函数中。

3、将子类构造函数中的共同代码删掉,改而调用新建的超类构造函数。

如果子类构造函数中的所有代码都是一样的,那么子类构造函数就只需要调用超类构造函数。

4、编译、测试。

如果日后子类构造函数再出现相同代码,你可以首先使用Extract Method将那部分提炼到一个独立函数中,然后使用Pull Up Method将该函数上移到超类。

四、Push Down Method(函数下移)

超类中的某个函数只与部分(而非全部)子类有关。

将这个函数移到相关的子类去。

动机

Push Down Method 与 Pull Up Method恰恰相反。当我有必要把某些行为从超类移至特定的子类时,我就使用 Push Down Method,它通常也只有在这种时候使用。使用Extract Subclass之后你可能会需要它。

做法

1、在所有子类中声明该函数,将超类中的函数本体复制到每一个子类函数中。

你可能需要将超类的某些字段声明为protected,让子类函数也能够访问他们。如果日后你也想把这些字段下移到子类,通常就可以那么做;否则应该使用超类提供的访问函数。如果访问函数并非public,你得将它声明为protected

2、删除超类中的函数

你可能必须修改调用端的某些变量声明或参数声明,以便能够使用子类。

如果有必要通过一个超类对象访问该函数,或你不想把该函数从任何子类中移除,再或超类是抽象类,那么你就可以在超类中把该函数声明为抽象函数。

3、编译、测试。

4、将该函数从所有不需要它的那些子类中删除。

5、编译、测试。

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



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

相关文章

不懂推荐算法也能设计推荐系统

本文以商业化应用推荐为例,告诉我们不懂推荐算法的产品,也能从产品侧出发, 设计出一款不错的推荐系统。 相信很多新手产品,看到算法二字,多是懵圈的。 什么排序算法、最短路径等都是相对传统的算法(注:传统是指科班出身的产品都会接触过)。但对于推荐算法,多数产品对着网上搜到的资源,都会无从下手。特别当某些推荐算法 和 “AI”扯上关系后,更是加大了理解的难度。 但,不了解推荐算法,就无法做推荐系

无人叉车3d激光slam多房间建图定位异常处理方案-墙体画线地图切分方案

墙体画线地图切分方案 针对问题:墙体两侧特征混淆误匹配,导致建图和定位偏差,表现为过门跳变、外月台走歪等 ·解决思路:预期的根治方案IGICP需要较长时间完成上线,先使用切分地图的工程化方案,即墙体两侧切分为不同地图,在某一侧只使用该侧地图进行定位 方案思路 切分原理:切分地图基于关键帧位置,而非点云。 理论基础:光照是直线的,一帧点云必定只能照射到墙的一侧,无法同时照到两侧实践考虑:关

活用c4d官方开发文档查询代码

当你问AI助手比如豆包,如何用python禁止掉xpresso标签时候,它会提示到 这时候要用到两个东西。https://developers.maxon.net/论坛搜索和开发文档 比如这里我就在官方找到正确的id描述 然后我就把参数标签换过来

poj 1258 Agri-Net(最小生成树模板代码)

感觉用这题来当模板更适合。 题意就是给你邻接矩阵求最小生成树啦。~ prim代码:效率很高。172k...0ms。 #include<stdio.h>#include<algorithm>using namespace std;const int MaxN = 101;const int INF = 0x3f3f3f3f;int g[MaxN][MaxN];int n

【生成模型系列(初级)】嵌入(Embedding)方程——自然语言处理的数学灵魂【通俗理解】

【通俗理解】嵌入(Embedding)方程——自然语言处理的数学灵魂 关键词提炼 #嵌入方程 #自然语言处理 #词向量 #机器学习 #神经网络 #向量空间模型 #Siri #Google翻译 #AlexNet 第一节:嵌入方程的类比与核心概念【尽可能通俗】 嵌入方程可以被看作是自然语言处理中的“翻译机”,它将文本中的单词或短语转换成计算机能够理解的数学形式,即向量。 正如翻译机将一种语言

怎么让1台电脑共享给7人同时流畅设计

在当今的创意设计与数字内容生产领域,图形工作站以其强大的计算能力、专业的图形处理能力和稳定的系统性能,成为了众多设计师、动画师、视频编辑师等创意工作者的必备工具。 设计团队面临资源有限,比如只有一台高性能电脑时,如何高效地让七人同时流畅地进行设计工作,便成为了一个亟待解决的问题。 一、硬件升级与配置 1.高性能处理器(CPU):选择多核、高线程的处理器,例如Intel的至强系列或AMD的Ry

计算机毕业设计 大学志愿填报系统 Java+SpringBoot+Vue 前后端分离 文档报告 代码讲解 安装调试

🍊作者:计算机编程-吉哥 🍊简介:专业从事JavaWeb程序开发,微信小程序开发,定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事,生活就是快乐的。 🍊心愿:点赞 👍 收藏 ⭐评论 📝 🍅 文末获取源码联系 👇🏻 精彩专栏推荐订阅 👇🏻 不然下次找不到哟~Java毕业设计项目~热门选题推荐《1000套》 目录 1.技术选型 2.开发工具 3.功能

POJ1269 判断2条直线的位置关系

题目大意:给两个点能够确定一条直线,题目给出两条直线(由4个点确定),要求判断出这两条直线的关系:平行,同线,相交。如果相交还要求出交点坐标。 解题思路: 先判断两条直线p1p2, q1q2是否共线, 如果不是,再判断 直线 是否平行, 如果还不是, 则两直线相交。  判断共线:  p1p2q1 共线 且 p1p2q2 共线 ,共线用叉乘为 0  来判断,  判断 平行:  p1p

代码随想录冲冲冲 Day39 动态规划Part7

198. 打家劫舍 dp数组的意义是在第i位的时候偷的最大钱数是多少 如果nums的size为0 总价值当然就是0 如果nums的size为1 总价值是nums[0] 遍历顺序就是从小到大遍历 之后是递推公式 对于dp[i]的最大价值来说有两种可能 1.偷第i个 那么最大价值就是dp[i-2]+nums[i] 2.不偷第i个 那么价值就是dp[i-1] 之后取这两个的最大值就是d

pip-tools:打造可重复、可控的 Python 开发环境,解决依赖关系,让代码更稳定

在 Python 开发中,管理依赖关系是一项繁琐且容易出错的任务。手动更新依赖版本、处理冲突、确保一致性等等,都可能让开发者感到头疼。而 pip-tools 为开发者提供了一套稳定可靠的解决方案。 什么是 pip-tools? pip-tools 是一组命令行工具,旨在简化 Python 依赖关系的管理,确保项目环境的稳定性和可重复性。它主要包含两个核心工具:pip-compile 和 pip