第三章:在何处重构。
决定何时重构以及何时停止重构与知道重构机制如何运转一样重要。
1、神秘代码:整洁代码最重要的一环就是好的名字。命名是编程中最难的两件事之一(扩展阅读:另一件是缓存失效)。
2、重复代码:注意是否有细微差异,以及其调用者等,这决定了我们要怎么去处理它。
3、过长函数:函数越长,越难理解。让小函数易于理解的关键还是在于良好的命名,这样我们只看函数名而不用看整段代码就知道这个函数在做什么,随意起的名字只会让我们浪费更多时间。作者说:每当感觉需要以注释来说明点什么的时候,我们就可以把要说明的东西写进一个独立的函数中,然后以其用途来命名(不要在意其函数名长度)。不过我们自己也应该看情况决定是否需要这么做(最后一条有说明)。
4、过长参数列表:使用类/传入完整对象/合并为一个对象都可以有效的缩短参数列表,需要我们自己看情况决定。
5、全局数据:因为从代码库的任何角落都可以修改它,类变量和单例也有这种问题。对全局变量最好封装起来,限制它的作用域。
6、可变数据:对数据的修改经常导致出乎意料的结果和难以发现的bug。可变数据的作用域越大,风险也越大,同全局数据。
7、发散式变化:指某个模块经常因为不同的原因在不同的方向上发生变化。
8、霰(xiàn)弹式修改:指如果每遇到某种变化,你都必须在许多不同的类内作出许多小修改。
9、依恋情节:在模块化时一个函数跟另一个模块中的函数或者数据交流的格外频繁,远胜于在自己所处模块内部的交流。最好的办法当然是,将他们合并到一起。
10、数据泥团:指那些你常常在很多地方可以见到的相同的三四项数据,例如:两个类中相同的字段、许多函数签名中相同的参数等。最好的办法就是新建一个类,这样可以消除大量的重复。
11、基本类型偏执:指大量的使用基本类型,而很少创建对自己的问题域有用的基本类型。例如:把钱当做普通数字来计算、计算物理量时无视单位等。
12、重复的switch:指在不同的地方反复使用同样的switch逻辑(也可能是连续的if/else语句)。最佳的解决办法就是多态。
13、循环语句:使用管道操作来替代。至于什么是管道操作,看了后边的示例,主要指代filter和map,iOS没有这东西,JavaScript和Java的同学应该了解。
14、冗赘的元素:指那些简单的不需要搞的复杂的代码。例如:某个函数的名字和它的实现代码看起来一模一样,或者某个类根本就是一个简单的函数。
15、夸夸其谈通用性:主要指那些你以为将来会用到的代码。
16、临时字段:指仅为某种特定情况而设的字段。
17、过长的消息链:最好的办法是,先观察消息链最终得到的对象是用来干什么的,然后选择性的重构。
18、中间人:指过度运用委托。
19、内幕交易:指为了减少耦合而建起高墙。在实际情况中,一定的数据交换不可避免,我们必须尽量减少内幕交易这种情况,把这种交换都放到明面上。
20、过大的类:观察一个大类的使用者。经常能找到如何拆分类的线索。
21、异曲同工的类:使用类的好处之一就是可以替换,今天用这个类,未来可以换成另外一个。
22、纯数据类:指它们拥有一些字段,以及用于访问这些字段的函数,除此之外一无长物。纯数据类常常意味着行为被放到了错误的地方。也就是说,只要把处理数据的行为放到纯数据类中,就能是情况大为改观。不过一个非常常见的特殊情况就是,这个纯数据记录对象被用于函数调用的返回结果,此时无需操作。
23、被拒绝的遗赠:指子类继承了超类的所有函数和数据,但是它可能不想或者不需要继承,或者只需要其中的几样。此处建议:如果子类继承了超类的实现,却不愿意支持超类的接口,那就是不能被接受的。拒绝继承超类的实现可以被接受。
24、注释:注释可以帮我们找到重构的点,看到注释应该先想是否可以尝试重构。有用的注释一般指用来记录将来的打算,或者你暂时没有把握的内容,或者你为什么这么做。其他的注释就试试重构吧。