代码的坏味道来源: 发布时间:星期五, 2009年10月2日 浏览:0次 评论:0
转载自:http://blog.csdn.net/chgaowei/archive/2009/10/02/4626950.aspx
《重构》第三章学习笔记 我们必须培养自己的判断力,来决定在什么时候进行重构。 1.1 Duplicate Code(重复代码)如果你在一个以上地点看到相同的程序结构,那么将他们合而为一会更好。 1.2 Long Method(过长函数)拥有短函数的对象会活得比较好,比较长。 间接层所能带来的全部益处:解释能力(可读性),共享能力(重用性),选择能力(?)。 现在OO 语言基本解决了函数调用所产生的开销。 “ 你应该更积极进去的分解函数。我们遵循这样一条原则:每当感觉需要以注释来说明点什么的时候,我们就把需要说明的东西写进一个函数中,并以其用途(而非实现手法)命名。我们可以对一组甚至短短一行代码(拥有复杂逻辑,难以理解)做这件事。哪怕替换后的函数调用动作比函数自身还长,只要函数名称能够解释其用途,我们也该毫不犹豫的这么做。关键不在于函数的长度,而在于“做什么”和“如何做”之间的语义距离。 ” “如何确定该提炼哪一段代码?一个很好的技巧是:寻找注释。它们通常是指出“代码用途和实现手法间的语义距离”的信号。如果代码需要用注释来说明其用途,那么就要考虑把这段代码提炼成独立的函数,并且用注释来为此函数命名。” 复杂条件式和循环液常常是提炼的信号。 1.3 Large Class(过大类)如果想利用单一的class 做太多的事情,其内往往会出现太多的 instance 变量。 如果class 中拥有太多的代码,也是“代码重复、混乱、死亡”的绝佳滋生点。
1.4 Long Parameter List(过长的参数列表)过长的产生导致程序难以理解。 1.5 Divergent Change(发散式变化)“ 一个class 受多个外界变化的影响 ”,则把这多个变化封装成一个新的类。即“ 将总是一起变化的东西放在一起 ” 针对外界某一变化所有相应的修改,都应该只发生在单一的class 中,而这个 class 的所有内容都应该反映该外界变化。总的思想就是,封装变化。这个地方和设计模式的想法是一致的。 1.6 Shotgun Surgery(散弹式修改)和发散式变化不同,每次遇到变化,都要在多个class 中进行小的修改以响应之。他们分散在多处,很容易出错。 这里的主要思想是集中变化。 散弹式修改指的是,“ 一种变化引发多个class 的修改 ”,发散式变化指的是“ 一个class 受多个外界变化的影响 ”。 这两种情况下,通过重构, 使“外界变化”和“待修改类”呈一对一关系 的理想境地。 1.7 Feature Envy(依恋情节)某个函数对其他类的数据的兴趣,高过对host class 的兴趣。即对其他的类的数据的依赖十分大。 1.8 Data Clumps(数据泥团)数据泥团指的是总是绑定在一起出现的数据。 一个好的评断方法:删除众多数据中的一项数据,其他数据是否是因而失去了意义?如果他们不再有意义:你应该为他们产生一个新的对象。 形成新的对象后,可以根据Feature Envy 将一些操作移至此对象中。 1.9 Primitive Obsession(基本型别偏执)建立多个很小,但是很灵活的对象。 1.10 Switch Statements( switch 惊悚现身)使用面向对象编程,要少用switch 和 case 语句。而是用多态来替换它。 1.11 Parallel Inheritance Hierarchies(平行继承体系)每当你为一个class 增加一个 subclass 的时候,必须为另一个 class 增加一个 subclass 。一般这两个 class 的前缀相同。 1.12 Lazy Class(冗赘类)类显得多余,没有价值。 1.13 Speculative Generality(夸夸其谈未来性)这个往往是过度设计的结果:对某种变化的应对,而这种变化没有发生。 1.14 Temporary Field(令人迷惑的暂时值域)变量只在特定的情形下有效,而并不是所有的情况下有效。很多情况下,这些值域应该不属于此class ,而应该单独的提取成新的类。 1.15 Message Chains(过度耦合的消息链)用户向一个对象索取另一个对象,然后在向后者索求另一个对象,然后在索求另一个对象——客户与查找过程的航行结构紧密耦合。 1.16 Middle Man(中间转手人)对象的基本特征之一就是封装——对外部世界隐藏实现细节——封装往往伴随委托。委托的过度运行,就导致了Middle Man 。 1.17 Inappropriate Intimacy (亲密关系)两个class 之间的关系过于亲密。比如,花大量的时间探究彼此的 private 成分。 1.18 Alternative Classes with Different Interface(异曲同工的类)类名不同,但是功能相似。 1.19 Incomplete Library Class(不完美的程序类库)基础类库无法满足实际的需求。 1.20 Data Class(纯稚的数据类)它们拥有一些值域,以及用于访问(读写)这些值域的函数,除此之外一无长物。 1.21 Refused Bequest(被拒绝的遗赠)子类不像继承父类的函数和数据,这往往是继承体系的错误。 如果子类复用父类的行为,但又不愿支持父类的接口,这种情况下Refused Bequest 的坏味道会很强烈。 1.22 Comments(过多的注释)注释其实是一种香味,更多的情况下它被用作除臭剂:即代码中出现坏味道(设计糟糕的代码),然后用注释“除臭”。这个时候我们应该对这些坏味道的代码进行重构,然后,你会发现注释变成了多余的。
当你感觉需要注释,请先尝试重构,试着让所有的注释都变得多余——代码本身就是自注释的。
注释可以用来记述“为什么做某事”、“打算做某事”、“无十足把握的区域”,而不必记录“怎么做”。
2 构筑测试体系如果你想进行重构,首要前提就是要拥有一个可靠的测试环境。 “编写优良的测试程序,可以极大的提高我的编程速度,即使不进行重构也是如此。” 2.1 自我测试代码(Self-testing Code )的价值“Class 应该包含他们自己的测试代码。” “每个Class 都有一个测试函数,并用它测试自己这个 Class 。” 确保所有的测试都完全自动化,让它们检查自己的测试结果。 只要写好一点功能,就立即添加测试。 一整组(a suite of )测试就是一个强大的“臭虫”侦测器,能够大大缩减查找“臭虫”所需要的时间。 “实际上,编写测试代码的最有用时机是在开始编程之前。当你需要添加特性的时候,先写相应的测试代码。听起来离经叛道,其实不然。填写测试代码其实就是问自己:添加这个功能需要做什么。编写测试代码还能使你把注意力集中于接口而非实现上头(永远是件好事)。预先写好的测试代码也为你的工作按上一个明确的结束标志:一旦测试代码运行正常,工作就可以结束了。”
0
相关文章读者评论发表评论 |
|