《重构-改善既有代码的设计》读书笔记
2015-01-20 12:28
323 查看
坏味道 | 特征 | 情况及处理方式 | 目标 | |
重复代码 | 1.重复的表达式 2.不同算法做相同的事 3.类似代码 | 同一个类的两个函数有相同表达式 | 重复代码提取为方法 | 相同表达式只在一个类的一个方法出现,供其他方法调用 |
兄弟类含有相同表达式 | 重复代码提取为方法 提升方法到父类 | |||
不相干类含有相同代码 | 提取为独立类供调用 | |||
过长函数 | 1.代码前面有注释 2.条件表达式 3.循环 | | 提取方法 | 每个方法只做一件事,方法要定义完善、命名准确 |
过大的类 | 1.一个类中有太多实例变量 2.一个类中有太多代码 | 部分字段之间相关性高 | 相关的字段和方法提取为类 | 每个类负责一组具有内在的相互关联的任务 |
某些字段和方法只被某些实例用到 | 这些字段和方法移到子类中 | |||
过长参数列 | 1.参数列过长 2.参数列变化频繁 | 方法可以通过其他方式获取该参数 | 让参数接受者自行获取该参数 | 只需要传给函数足够的、让其可以从中获取自己需要的东西就行了 |
同一对象的若干属性作为参数 | 在不使依赖恶化的情况下,使用整个对象作为参数 | |||
被调用函数使用了另一个对象的很多属性 | 将方法移动到该对象中 | |||
某些数据缺乏归属对象 | 首先创建对象 | |||
发散式变化 | 一个类受多种变化的影响 | 类经常因为不同的原因在不同的方向上发生变化 | 将特定原因造成的所有变化提取为一个新类 | 针对某一外界变化的所有修改,只应发生在单一类中,而这个类中所有的内容都应反映此变化 |
散弹式修改 | 一种变化引发多个类的修改 | 某种变化需要在许多不同的类中做出小修改 | 把所有需要修改的代码放进同一个类中 | 针对某一外界变化的所有修改,只应发生在单一类中,而这个类中所有的内容都应反映此变化 |
依恋情结 | 一个函数使用其他类属性比使用自身类属性还要多 | 某个函数从另一个对象调用了几乎半打的取值函数 | 将依恋代码提取为单独方法,移动到另一对象 | 将数据和对数据的操作行为包装在一起 |
数据泥团 | 同时使用的相关数据并未以类的方式组织 1.两个类中相同的字段 2.许多函数中相同的参数 | | 先将字段提取为类,再缩减函数签名中的参数 | 总是绑在一起的数据应该拥有属于它们自己的对象 |
基本类型偏执 | 过多使用基本类型 | 总是被放在一起的基本类型字段 | 提取类 | 将单独存在的数据值转换为对象 |
参数列中有基本类型 | 提取参数对象 | |||
数组中容纳了不同的对象,需要从数组中挑选数据 | 用对象取代数组 | |||
基本数据是类型码 | 使用类替换类型码 | |||
带条件表达式的类型码 | 使用继承类替换类型码 | |||
Switch语句 | 相同的switch、case语句散布于不同地方 | 根据类型码进行选择的switch | 使用多态替代switch | 避免到处做相同的修改 |
单一函数中有switch | 使用显式的方法取代参数 | |||
平行继承体系 | 1.为某个类增加子类时,必须为另一个类增加子类 2.某个继承体系类名前缀和另一个继承体系类名前缀相同 | | 一个继承体系中的实例引用另一个继承体系中的实例,然后迁移成员 | 避免到处做相同的修改 |
冗赘类 | 类无所事事 | 父类和子类无太大差别 | 将它们合为一体 | |
某个类没有做太多事情 | 将这个类所有成员移到另一个类中,删除它 | |||
夸夸其谈未来性 | | 某个抽象类没有太大作用 | 将父子类合并 | |
不必要的委托 | 将这个类所有成员移到另一个类中,删除它 | |||
函数的某些参数未用上 | 移除参数 | |||
函数名称带有多余的抽象意味 | 重命名函数名 | |||
函数只被测试方法调用 | 连同测试代码一并删除 | |||
令人迷惑的暂时字段 | 1.某个实例字段仅为某种情况而设 2.某些实例字段仅为某个函数的复杂算法少传参数而设 | | 提取单独的类,封装相关代码 | |
过度耦合的消息链 | 一长串的getThis或临时变量 | 客户类通过一个委托类来取得另一个对象 | 隐藏委托 | 消除耦合 |
中间人 | 某个类接口有大量的函数都委托给其他类,过度使用委托 | 有一半的函数 | 移除中间人 | |
少数几个函数 | 直接调用 | |||
中间人还有其他行为 | 让委托类继承受托类 | |||
狎昵关系 | 某个类需要了解另一个类的私有成员 | 子类过分了解超类 | 将继承改为委托,把子类从继承体系移出 | 封装 |
类之间双向关联 | 去掉不必要的关联 | |||
类之间有共同点 | 提取新类 | |||
异曲同工的类 | 两个函数做同一件事,但是签名不同 | | 合并 | |
不完美的类库 | 类库函数构造的不够好,又不能修改它们 | 想修改一两个函数 | 在调用类增加函数 | |
想添加一大堆额外行为 | 使用子类或包装类 | |||
幼稚的数据类 | 某个类除了字段,就是字段访问器、设置器 | | 1.用访问器取代public字段 2.恰当封装集合 3.移除不需要的设置器 4.搬移对访问器、设置器调用方法到此类 5.隐藏访问器、设置器 | 封装 |
被拒绝的馈赠 | 派生类仅使用了基类很少一部分成员函数 | 子类拒绝继承超类接口 | 使用委托替代继承 | |
过多的注释 | 一段代码有着长长的注释 | | 消除各种坏味道 | |
重构,绝对是写程序过程中最重要的事之一。在写程序之前我们不可能事先了解所有的需求,设计肯定会有考虑不周的地方,而且随着项目需求的修改,也有可能原来的设计已经被改得面目全非了。更何况,我们很少有机会从头到尾完成一个项目,基本上都是接手别人的代码,即使这个项目是从头参与的,也有可能接手其他组员的代码。我们都有过这样的经验,看到别人的代码时感觉就像屎一样,有一种强烈的想重写的冲动,但一定要压制住这种冲动,你完全重写,可能比原来的好一点,但浪费时间不说,还有可能引入原来不存在的Bug,而且,你不一定比原来设计得好,也许原来的设计考虑到了一些你没考虑到的情况。我们写的代码,终有一天也会被别人接手,很可能到时别人会有和我们现在一样的冲动。所以,我们要做的是重构,从小范围的重构开始。
重构不只可以改善既有的设计,还可以帮助我们理解原来很难理解的流程。比如一个复杂的条件表达式,我们可能需要很久才能看明白这个表达式的作用,还可能看了好久终于看明白了,过了没多长时间又忘了,现在还要从头看,如果我们把这个表达式运用Extract Method抽象出来,并起一个易于理解的名字,如果函数名字起得好,下次当我们再看到这段代码时,不用看逻辑我们就知道这个函数是做什么的。如果对这个函数内所有难于理解的地方我们做了适当的重构,把每个细小的逻辑抽象成一个小函数并起一个容易理解的名字,当我们看代码时就有可能像看注释一样,不用再像以前一样通过看代码的实现来猜测这段代码到底是做什么的,好的代码胜过注释,毕竟注释还是有可能更新不及时的。
《重构,改善既有代码的设计》,这是一部经典之作,相信很多人都听过或看过,看这本书时会发现,书中讲的都是一些很简单的东西,而且很多东西就是我们平时在做的,只是作者把它们总结了起来。比如说Rename Field,就是对不易理解其作用的字段起一个易于理解的名字,这个肯定我们都做过,但是更多时候,我们是对这种字段视而不见,比如曾经花了很久没搞明白代码的字段"IP"是什么的缩写,最后发现竟然是“INPUT”。看过这本书的收获是,让重构融于整个写代码的过程中,让重构不再作为一项独立的任务,而是在写代码的过程中随时随地的进行,一个函数不容易理解,重构;添加新功能时很不方便,重构,使添加新功能变得理解。
这本书是用Java写的,而且Java的版本很老。
书中的一些东西说得太绝对,比如说看到switch就重构,但这是不现实的,比如说Android开发,菜单的onOptionsItemSelected,这个肯定是重构不了的;对于很多控件的onClickListener,还是统一设置一个Listener并通过ViewID区分方便点,尤其是在Adapter的getView中,针对每个控件new一个onClickListener会生成太多对象。当然,不是说这个重构手法无效,而是这个手法提醒我们,当看到这样的情况时需要认真考虑一下,当前的情况是否需要重构,如果确定不需要,就那样好了。
但是有些东西还是很值得注意的,比如封装集合(Encapsulate Collection),当调用者请求一个类的一个集合对象时,我们最好不要返回这个集合对象,而是返回这个集合对像的一个不可修改的副本,并增加添加/移除数据的函数。比如Android开发的Adapter,我们经常会为了方便给Adapter添加返回数据集合与设置数据集合的方法,但这是不安全的,我们不能确定调用者获得这个集合后会做什么事情,如果调用者修改了这个集合的内容我们也对其一无所知,在Android中,如果调用者在非UI线程获得了Adapter列表的数据并修改是会出问题的。
重构前,先检查自己是否有一套可靠的测试机制。这些测试必须有自我检验的能力,毕竟重构可能破坏掉一些东西,我们要靠测试帮助我们发现这些问题,不要因为测试无法捕捉所有bug就不写测试, 因为测试的确可以捕捉到大多数bug。不过,说来惭愧,我很少写测试,尤其是Android项目。
书中全是一些很简单的手法,我相信,我们肯定都用过其中的大部分重构手法,只是没有察觉。这本书只是对其进行了一个总结,并让我们意识到重构这项技能,并让重构融入我们整个写程序的过程中,让重构无处不在。
书中的一些重构手法,在我感觉可能就不算是重构手法,比如给函数添加参数,如果参数不够又必须添加,我们肯定会添加的,这算是功能修改还是重构,随便怎么理解吧,不过作为笔记,还是把所有这些都记录下来了。
对这本书的笔记只有三个图,是对书中所有重构手法列表的一个简单记录,方便以后查阅,至于具体操作步骤或例子,以后想看时翻书就行了,或都网上也可以搜到的。下面这个链接是一个C#版本关于重构的系列,但不是这本书的C#版本,其中的手法大都是相同的,圣殿骑士:31天重构系列。
重构列表:
要点列表:
代码坏味:
转载自:http://www.cnblogs.com/angeldevil/p/3601730.html
参考:http://blog.csdn.net/cdl2008sky/article/details/4396183
相关文章推荐
- 《重构-改善既有代码的设计》读书笔记(一)
- 《重构-改善既有代码的设计》读书笔记
- 『重构--改善既有代码的设计』读书笔记----代码坏味道【3】
- 『重构--改善既有代码的设计』读书笔记----Extract Method
- 《重构 改善既有代码的设计》读书笔记2
- 重构 改善既有代码的设计(读书笔记3)
- 『重构--改善既有代码的设计』读书笔记----代码坏味道【2】
- 『重构--改善既有代码的设计』读书笔记----Inline Temp
- 『重构--改善既有代码的设计』读书笔记----代码坏味道【5】
- 《重构--改善既有代码的设计》读书笔记
- 《重构-改善既有代码的设计》读书笔记
- 《重构--改善既有代码的设计》读书笔记之三:分解并重组statement() part2
- 『重构--改善既有代码的设计』读书笔记----Introduce Explaning Variable
- 《重构-改善既有的代码设计》读书笔记
- 《重构,改善既有代码的设计》读书笔记
- 《重构--改善既有代码的设计》读书笔记之五:运用多态取代条件逻辑(if/else , switch)
- 《重构--改善既有代码的设计》读书笔记之一:起始代码之C++ Version
- 『重构--改善既有代码的设计』读书笔记----代码坏味道【4】
- 《重构——改善现有代码的设计》 读书笔记
- 『重构--改善既有代码的设计』读书笔记----Inline Method