【《重构 改善既有代码的设计》学习笔记7】在对象之间搬移特性「建议收藏」

本篇文章的内容来自《重构 改善既有代码的设计》一书学习笔记整理并且加上自己的浅显的思考总结!在对象之间搬移特性,核心就是: 决定把责任放在哪儿,重点关注责任,也就是尽量一个类之处理一类事情,或者是某个责任和这个类关系不大,就将此责任移动到关系大的类中。本篇内容两两放在一起,互相对比学习。也更方便理解和记忆。1、搬移函数(Move Method)& 搬移字段(Move field…

大家好,又见面了,我是全栈君。

本篇文章的内容来自《重构 改善既有代码的设计》一书学习笔记整理并且加上自己的浅显的思考总结!

在对象之间搬移特性,核心就是: 决定把责任放在哪儿,重点关注责任,也就是尽量一个类之处理一类事情,或者是某个责任和这个类关系不大,就将此责任移动到关系大的类中。

本篇内容两两放在一起,互相对比学习。也更方便理解和记忆。

1、搬移函数(Move Method)& 搬移字段(Move field)

概要

这两个重构手法,可以类比去学习,本质都是在程序中,有个函数/字段与所在类之外的另一个类有更多的交流。

搬移函数:在目标类中建立一个有着类似行为的新函数,将旧函数变成一个单纯的委托函数,或者将旧函数移除。

搬移函数

搬移字段:在目标类中新建一个字段,修改源字段的所有用户,令它们使用新字段。

搬移字段

动机

”搬移函数“ 的方法在重构中一个很重要的理论支柱,在类中间移动状态(字段)和行为(方法),更是重构中比不可少的措施。随着系统的发展,会发现之前的合理正确的设计策略,到目前来看存在一些问题(不正确)。此时可以进行搬移函数 或者 搬移字段

做法

书中的内容这里不详细展开,只是谈下自己的理解。

♢ 首先找到要移动的函数/字段,移到到目标类中 。(这一步我认为是比较考验业务功能以及对代码的理解力)

♢ 移动完之后,修改所有引用的旧函数/字段的地方,使用新的函数/字段。

♢编译、测试

范例

  • 搬移函数:委托/移除旧函数

搬移函数:委托/移除旧函数 范例

:目标函数需要源类的多个特性,可以使用将源对象传递给目标函数。不过如果目标函数需要太多源类特性,则就得进一步重构。

  • 搬移字段

搬移字段 范例

2、提炼类(Extract Class) & 类内联化(Inline Class)

概要

本质就是:类做了自己不该做的事。

提炼类:**某个类做了应该由两个类做的事。**建立一个新类,将字段和函数从旧类移到新类。(分离)

【《重构 改善既有代码的设计》学习笔记7】在对象之间搬移特性「建议收藏」

类内联化某个类没有做太多事情。 将这个类的所有特性搬移到另一个类中,然后移除原类。(合并)07-2019-03-02_17-02-40-05

动机

一个类应该有清楚的抽象。提炼类和类内联化,两个方式刚好相反。提炼类:类含有大量函数和数据,不好理解,需将它们分离到单独的类中,而类内联化:如果一个类不再承担足够责任,就不再有单独存在的理由。

做法

一个是提炼一个内联化,最主要的是要找到分离的函数和数据和内化的类,其他重构的操作就简单了。具体步骤省略。

范例

  • 提炼类

提炼类 范例

  • 类内联化

和提炼类刚好相反。

内联化 范例

上面两种方式,要在全面理解代码的基础上在进行重构,要求重构的能力还是比较高的。一般项目的代码中的重构不会像上面的例子这么简单。例子只是用来简单说明这种重构方法。

我看到上面的两个重构手法的时候,第一感觉,搞来搞去,有点晕了! 但是细细品读和理解,别有一番滋味。

3、隐藏“委托关系”(Hide Delegate) & 移除中间人(Remove Middle Man)

概要

本质:是否要使用委托关系。两个方法对立。

隐藏“委托关系”:使用委托关系,在服务类上建立客户所需的所有函数,用以隐藏委托关系。

移除中间人:让客户直接调用委托类。

【《重构 改善既有代码的设计》学习笔记7】在对象之间搬移特性「建议收藏」

动机

隐藏“委托关系” : “封装” 即使不是 对象的最关键的特性,也是最关键特性之一。封装 意味着每个对象都应该尽可能少的了解系统的其他部分,如此一来,发生变化。需要了解变化的对象就会更少。

移除中间人:封装 也是要付出代价的,代价就是:每当客户要使用受委托的特性和功能的新特性时候,就必须在服务端添加一个简单的委托函数。很难说什么程度的隐藏才是合适的,在系统的运行过程中不断进行调整。

重构的意义在于:你永远不必说对不起,只要把出问题的地方修补好就行了。

做法

具体略,可参看范例!

范例

  • 隐藏-委托关系

隐藏-委托关系 范例

  • 移除中间人

移除中间人和隐藏 委托关系刚好相反。

移除中间人 范例

4、引入外加函数(Introduce Foregin Method)

概要

你需要为提供服务的类增加一个函数,但你无法修改这个类。在客户类中建立一个函数,并以第一参数形式传入一个服务类。【具体可以看示例】

动机

你在使用一个类,它真的很好,为你提供了需要的所有服务。但是当你需要一项新的服务时候,这个类却无法提供。一般发生在你不能修改这个类的源码。如果可以修改源码,这个外加函数 也就不必使用了。

请记住: 外加函数终归是权宜之计,如果可能,应该将这些函数搬移到它们的理想家园。

做法

具体看范例!

范例

可以理解为,Date有获取 年 、月 、日的服务,但是没有获取当前日期吓一天的日期的能力,而你又不能修改Date的源码,则在客户端加外加一个方法,获取当前日期的下一天的日期。(感觉有点像日期工具类)

外加函数 范例

5、引入本地扩展(Introduce Local Extension)

概要

你需要为服务类提供 一些额外函数,但你无法修改这个类。建立一个新类,使它包含这些额外额函数,让这个扩展品成为源类的子类或者包装类。

动机

项目的发展,有时候你需要一些方法,但是你又不能修改源码,因为要添加的函数多,外加函数很难控制它们。 此时可以使用 子类化 和 包装 两种标准的对象技术,这两种统一称为 本地扩展。

本地扩展 坚持“函数和数据应该统一封装”的原则。在子类和包装类选择的时候,通常选择子类,这样工作量小。

做法

建立子类或者包装类,具体看范例。

范例

  • 子类法

子类法 范例

  • 包装类

包装类需要在包装类中为原始类的所有函数提供 委托函数,比较枯燥乏味。 并且要注意的是,包装类要可以接受包装类或原始类的对象。

包装类 范例

总结

本篇的学习总结是按照对比的方式,最后的这个虽然没有放在一起,但是本质上还是有一点相同,就是在新增功能的你不能修改原服务类的代码,只能进行扩展,如果扩展的少,则使用外加函数,如果建立大量的外加函数,并发现许多类也需要同样的外加函数时候,则考虑使用引用本地扩展的方法。

本章的内容个人觉得还是相对较难,难的不是知识点,而是对代码的设计和理解的能力,什么时候进行重构,怎么样的情况下选择怎么样的重构方法,就本章这几个重构方法,到底如何在真实的项目代码进行操作,如何才能balance,这才是难点。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/121048.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • linux查看GCC版本

    linux查看GCC版本gcc-v打印出你使用gcc的版本信息 gcc-otesttest.c就会编译test.c,生成可执行文件test然后./test就会运行test

    2022年6月26日
    28
  • mysql初始化步骤_MySQL初始化步骤_MySQL

    mysql初始化步骤_MySQL初始化步骤_MySQLbitsCN comMySQL 初始化步骤新手肯定在刚刚使用 MySQL 的时候 肯定像我会遇到 PHP 无法连接数据库的问题 现在就把所要做的整理一下 前提是你已经将 mysql 的工作目录加入到环境变量 初始化步骤如下 为 root 用户设置密码 sql mysqladmin urootpasswor new password 使用新密码替换命令行中的 new password 删除匿名用户 s

    2025年12月12日
    3
  • 计算机等级二级java试题(计算机二级考试题库)

    第一章数据结构与算法【考点1】算法的基本概念1、算法:是指一组有穷的指令集,是解题方案的准确而完整的描述。算法不等于程序,也不等于计算方法。2、算法的基本特征:1)确定性,算法中每一步骤都必须有明确定义,不允许有多义性;2)有穷性,算法必须能在有限的时间内做完,即能在执行有限个步骤后终止;3)可行性,算法原则上能够精确地执行;4)拥有足够的情报。3、算法的组成…

    2022年4月10日
    92
  • 单片机入门到高级开挂学习路径(附教程+工具)[通俗易懂]

    单片机入门到高级开挂学习路径(附教程+工具)[通俗易懂]一、先帮大家解答几个问题:1.单片机是什么?答:单片机就是一个微型CPU,把程序烧录芯片里面,通过控制不同的外围电路实现不同产品的功能。2.学单片机编程对数学英语有要求吗?答:数学会基本的加减乘除就行,英语会认单词a-z就行,很多外行人看到代码里一堆英文就头嗡嗡响,其实不然,只有少数语法是固定的,大多数英文都是工程师自己定义的,比如大神你也可以定义成DaShen(中文缩写)。那很多人此时就开始质疑,当初这么辛苦学数学和英语到底是为毛?数学和英语不是单片机开发的门槛,但却决定你以后能达到的高度,

    2022年6月10日
    60
  • cubieboard 用户 密码 root「建议收藏」

    cubieboard 用户 密码 root「建议收藏」因为不是超级用户root,所以你进行任何操作都要使用sudo在命令的前面。启用root的方法:sudopasswdroot输入新的root密码2次,确认后。就激活了root账户,就可以使用root登录,以后就具备了最高权限。先解除root锁定,为root用户设置密码#sudopasswdPassword:EnternewUNIXpasswo

    2022年7月22日
    15
  • C#的封装_封装元器件

    C#的封装_封装元器件封装:即隐藏对象的属性和实现细节,仅对外公开接口,控制在程序中属性的读和修改的访问级别;将抽象得到的数据和行为(或功能)相结合,形成一个有机的整体,也就是将数据与操作数据的源代码进行有机的结合,形成“类”,其中数据和函数都是类的成员。封装的作用:封装最主要的功能在于我们能修改自己的实现代码,而不用修改那些调用我们代码的程序片段。适当的封装可以让程式码更容易理解与维护,也加强了程式码的安全性,使不同类之间的相互影响减少到最低限度,进而增强数据的安全性和简化程序的编写工作封装的优点:1.良好的封装能够减少

    2025年10月12日
    2

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号