大家好,又见面了,我是全栈君。
在对象之间搬移特性,核心就是: 决定把责任放在哪儿,重点关注责任,也就是尽量一个类之处理一类事情,或者是某个责任和这个类关系不大,就将此责任移动到关系大的类中。
本篇内容两两放在一起,互相对比学习。也更方便理解和记忆。
1、搬移函数(Move Method)& 搬移字段(Move field)
概要
这两个重构手法,可以类比去学习,本质都是在程序中,有个函数/字段与所在类之外的另一个类有更多的交流。
搬移函数:在目标类中建立一个有着类似行为的新函数,将旧函数变成一个单纯的委托函数,或者将旧函数移除。
搬移字段:在目标类中新建一个字段,修改源字段的所有用户,令它们使用新字段。
动机
”搬移函数“ 的方法在重构中一个很重要的理论支柱,在类中间移动状态(字段)和行为(方法),更是重构中比不可少的措施。随着系统的发展,会发现之前的合理正确的设计策略,到目前来看存在一些问题(不正确)。此时可以进行搬移函数
或者 搬移字段
。
做法
书中的内容这里不详细展开,只是谈下自己的理解。
♢ 首先找到要移动的函数/字段,移到到目标类中 。(这一步我认为是比较考验业务功能以及对代码的理解力)
♢ 移动完之后,修改所有引用的旧函数/字段的地方,使用新的函数/字段。
♢编译、测试
范例
- 搬移函数:委托/移除旧函数
注:目标函数需要源类的多个特性,可以使用将源对象传递给目标函数。不过如果目标函数需要太多源类特性,则就得进一步重构。
- 搬移字段
2、提炼类(Extract Class) & 类内联化(Inline Class)
概要
本质就是:类做了自己不该做的事。
提炼类:**某个类做了应该由两个类做的事。**建立一个新类,将字段和函数从旧类移到新类。(分离)
类内联化:某个类没有做太多事情。 将这个类的所有特性搬移到另一个类中,然后移除原类。(合并)
动机
一个类应该有清楚的抽象。提炼类和类内联化,两个方式刚好相反。提炼类:类含有大量函数和数据,不好理解,需将它们分离到单独的类中,而类内联化:如果一个类不再承担足够责任,就不再有单独存在的理由。
做法
一个是提炼一个内联化,最主要的是要找到分离的函数和数据和内化的类,其他重构的操作就简单了。具体步骤省略。
范例
- 提炼类
- 类内联化
和提炼类刚好相反。
上面两种方式,要在全面理解代码的基础上在进行重构,要求重构的能力还是比较高的。一般项目的代码中的重构不会像上面的例子这么简单。例子只是用来简单说明这种重构方法。
我看到上面的两个重构手法的时候,第一感觉,搞来搞去,有点晕了! 但是细细品读和理解,别有一番滋味。
3、隐藏“委托关系”(Hide Delegate) & 移除中间人(Remove Middle Man)
概要
本质:是否要使用委托关系。两个方法对立。
隐藏“委托关系”:使用委托关系,在服务类上建立客户所需的所有函数,用以隐藏委托关系。
移除中间人:让客户直接调用委托类。
动机
隐藏“委托关系” : “封装” 即使不是 对象的最关键的特性,也是最关键特性之一。封装 意味着每个对象都应该尽可能少的了解系统的其他部分,如此一来,发生变化。需要了解变化的对象就会更少。
移除中间人:封装 也是要付出代价的,代价就是:每当客户要使用受委托的特性和功能的新特性时候,就必须在服务端添加一个简单的委托函数。很难说什么程度的隐藏才是合适的,在系统的运行过程中不断进行调整。
重构的意义在于:你永远不必说对不起,只要把出问题的地方修补好就行了。
做法
具体略,可参看范例!
范例
- 隐藏-委托关系
- 移除中间人
移除中间人和隐藏 委托关系刚好相反。
4、引入外加函数(Introduce Foregin Method)
概要
你需要为提供服务的类增加一个函数,但你无法修改这个类。在客户类中建立一个函数,并以第一参数形式传入一个服务类。【具体可以看示例】
动机
你在使用一个类,它真的很好,为你提供了需要的所有服务。但是当你需要一项新的服务时候,这个类却无法提供。一般发生在你不能修改这个类的源码。如果可以修改源码,这个外加函数 也就不必使用了。
请记住: 外加函数终归是权宜之计,如果可能,应该将这些函数搬移到它们的理想家园。
做法
具体看范例!
范例
可以理解为,Date有获取 年 、月 、日的服务,但是没有获取当前日期吓一天的日期的能力,而你又不能修改Date的源码,则在客户端加外加一个方法,获取当前日期的下一天的日期。(感觉有点像日期工具类)
5、引入本地扩展(Introduce Local Extension)
概要
你需要为服务类提供 一些额外函数,但你无法修改这个类。建立一个新类,使它包含这些额外额函数,让这个扩展品成为源类的子类或者包装类。
动机
项目的发展,有时候你需要一些方法,但是你又不能修改源码,因为要添加的函数多,外加函数很难控制它们。 此时可以使用 子类化 和 包装 两种标准的对象技术,这两种统一称为 本地扩展。
本地扩展 坚持“函数和数据应该统一封装”的原则。在子类和包装类选择的时候,通常选择子类,这样工作量小。
做法
建立子类或者包装类,具体看范例。
范例
- 子类法
- 包装类
包装类需要在包装类中为原始类的所有函数提供 委托函数,比较枯燥乏味。 并且要注意的是,包装类要可以接受包装类或原始类的对象。
总结
本篇的学习总结是按照对比的方式,最后的这个虽然没有放在一起,但是本质上还是有一点相同,就是在新增功能的你不能修改原服务类的代码,只能进行扩展,如果扩展的少,则使用外加函数,如果建立大量的外加函数,并发现许多类也需要同样的外加函数时候,则考虑使用引用本地扩展的方法。
本章的内容个人觉得还是相对较难,难的不是知识点,而是对代码的设计和理解的能力,什么时候进行重构,怎么样的情况下选择怎么样的重构方法,就本章这几个重构方法,到底如何在真实的项目代码进行操作,如何才能balance,这才是难点。
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/121048.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...