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

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

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

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

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

概要

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

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

搬移函数

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

搬移字段

动机

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

做法

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

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

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

♢编译、测试

范例

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

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

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

  • 搬移字段

搬移字段 范例

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

概要

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

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

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

动机

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

做法

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

范例

  • 提炼类

提炼类 范例

  • 类内联化

和提炼类刚好相反。

内联化 范例

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

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

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

概要

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

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

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

动机

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

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

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

做法

具体略,可参看范例!

范例

  • 隐藏-委托关系

隐藏-委托关系 范例

  • 移除中间人

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

移除中间人 范例

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

概要

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

动机

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

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

做法

具体看范例!

范例

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

外加函数 范例

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

概要

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

动机

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

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

做法

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

范例

  • 子类法

子类法 范例

  • 包装类

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

包装类 范例

总结

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

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

已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 成长之路 设计师:Amelia_0503 返回首页