重构读书笔记 第3章 代码的坏味道

时间:2021-11-28 17:51:37

第3章代码的坏味道

1 Duplicated Code重复代码

a同一个类的两个函数还有相同的表达式;提炼代码

b两个互为兄弟的子类内含有相同的表达式;可以提炼相同代码,并放到父类中;   如果只是代码间相似,并非完全相同;那么可以将相似部分和差异部分拆开,构成单独的函数,然后你可以使用模板方法的设计模式。

c如果两个毫不相关的类中出现重复代码;则可以将重复代码提炼成一个函数放到一个独立类中或者只放在某一个类中,然后其他类都去调用这个函数

 

2 Long Method过长函数

a 函数过长,需要变小;

b 大量临时变量和参数;

c 条件表达式和循环;

一条原则:每当感觉需要以注释来说明点什么的时候,我们就把需要说明的东西写进一个独立函数中,并以其用途(而非实现手法)命名。哪怕替换后的函数调用动作比函数自身还长,只要函数名称能够解释其用途,我们也该毫不犹豫的那么做。关键不在于函数的长度,而在于函数“做什么”和“如何做”之间的语义距离。

 

3 Large Class过大的类

a 单个类太大,太多的实例变量等;提炼;

b 类内太多代码;分解函数;

如果有五个“百行函数”,它们之间很多代码都相同,那么或许你可以把它们编程五个“十行函数”和十个提炼出来的“双行函数”。

 

4 Long Parameter List过长参数列

a太长参数列表,难以理解,易出错;用对象做参数来减少参数个数;

b 若向对象发送请求就可以取代参数;使用对象重构;

c 若一堆数据来自同一对象;用该对象替换;

d 例外,若向对象请求造成依赖关系;避免依赖过重,用数据单独作为参数;

有了对象,就不必把函数需要的所有东西都以参数传递给它了,只需传给它足够的、让函数能从中获得自己需要的东西就行了。

这里有一个重要的例外:有时候你明显不希望造成“被调用对象”与“较大对象”间的某种依赖关系。这时候将数据从对象中拆解出来单独作为参数,也很合情合理。

 

5 Divergent Change发散式变化

a 某个类以不同原因在不同方向上发生变化,需要修改多个函数;将该对象分解成两个更好,让每个对象只因一种变化而修改;

针对某一外界变化的所有相应修改,都只应该发生在单一类中,而这个新类内的所有内容都应该反应次变化。

 
6 Shotgun Surgery霰弹式修改

a 遇到变化,需要修改的代码散步四处,难查找,易忘记(一种变化引发多个类相应修改);修改的代码放入一个类中,若无,就创建;

如果每遇到某种变化,你都必须在许多不同的类内做出许多小修改,这种情况下,可以把所有需要修改的代码放进同一个类,如果没有合适的类可放,就创造一个。

 

7 Feature Envy依恋情节

a函数对某个类的兴趣高过对自己所处类的兴趣,从别人那调用过多;判断哪个类拥有最多被此函数实用的数据,然后就把这个函数和那些数据摆在一起

对象技术的全部要点在于:这是一种“将数据和对数据的操作行为包装在一起”的技术。

最根本的原则是:将总是一起变化的东西放在一块。

 

8 Data Clupms数据泥团

a 两个类含义相同的字段,或者函数含有相同的参数;提炼这对象中;

总是绑在一起的数据应该拥有属于它们自己的对象

一个好的评判办法是:删掉众多数据中的一项,其他数据有没有因此而失去意义?如果他们不再有意义,这就是一个明确信号:你应该为它们产生一个新对象。

 

9 Primitive Obsession基本类型偏执

a 不愿使用对象,而使用基本类型;将数据组织成有意义的形式,不偏执于基本类型;

对象技术的新手通常不愿意在小任务上运用小对象。

如果你有一组应该总是被放在一起的字段(基本类型的数据),那么可以尝试将这组数据放到一个单独类中变成结构类型的数据

 

10 Switch Statements switch语句

a根据类型码选择相关的函数或类;多态解决;

b单一函数中选择事例;多态杀鸡牛刀了;

少用switch(或case)语句。从本质上说,switch语句的问题在于重复。

 

11 Parallel Inherutance Hierarchies平行继承体系

a 为某个类增加子类,必须也为另一个类增加子类;让一个继承体系的实例引用另一个继承体系的实例。

如果你发现某个继承体系的类名称前缀和另一个继承体系的类名称前缀完全相同;

 

12 Lazy Class冗赘类

a 一个类或组件没有太大的价值,不值其身价;想办法让其消失

 

13 Speculative Generrality夸夸其谈未来性

a 非必要的事,目前未被用到的;想办法消除

当有人说“噢,我想我们总有一天需要做这件事”,并因而企图以各式各样的钩子和特殊情况来处理一些非必要的事情。

 

14 Temporary Field令人迷惑的临时字段

a 某些实例变量为特定情况下设(所有对象的所有变量都应该被用到);把该实例变量的相关代码移至新家;

b 类中某个算法设置的变量,特定情况下有用;将这些变量移动至新类中;

 

15 Message Chains过度耦合的消息链

a 过长的消息链;观察消息链最终对象用处,提炼到独立函数中,将该函数推入到消息链;

 

16 Middle Man中间人

a 过度的委托;减少“不干实事”的函数,放进调用端;

 

17 Inappropriate Intimacy狎昵关系

a 两个类过于亲密;

b 两个类是在情投意合;提炼至新类中;

c 继承体系;

 
18 Alternative Classes with DifferentInterfaces异曲同工的类

a 两个函数做同一件事,函数签名不同;根据用途重新命名;

b 必须;移动至超类中;

 

19 Incomplete Library Class不完美的类库

a 使用类库,需要修改类库的某些函数;

 

20 Data Class纯稚的数据类

a 纯数据的类;字段以及容器需要封装;

b 找到取值和设值得地方;将其调用行为搬至这里,承担一定责任;

纯稚的数据类是指:它们拥有一些字段,以及用于访问(读写)这些字段的函数,除此之外一无长物。

这种类如果get/set方法均是public的,则需要引起注意,应该进行适当的封装,而不是全部公有化。

 

21 Refused Bequest被拒绝的遗赠

a 子类应该继承超类的函数和数据,若有些用不到;应该为该子类建兄弟类,把用不到的放入其中,将父类下放到兄弟类,父类持有的是共享的部分;

子类应该继承超类的函数和数据。但如果他们不想或不需要继承所有的函数和数据,则应该为这个子类新建一个兄弟类,把所有用不到的函数和数据放到兄弟类中,他们共享的数据和函数则放到共同的超类中。

 

22 Comments过多的注释

a 需要注释;

       注释解释代码;extract Method

       注释解释行为;rename

       注释解释需求规格;introduceAssertion

b 注释存在;标记将来的打算活着无把握的区域;

当你感觉需要撰写注释时,请先尝试重构,试着让所有注释都变得多余

如果你不知道该做什么的,这才是注释的良好运用时机。