说说什么是重构(一)重构的起点

来源:互联网 发布:淘宝c店保证金 编辑:程序博客网 时间:2024/05/16 08:33



最近,在看一本叫做《重构:改善既有代码的设计》的书,虽然是电子版的,但是依然不影响看书的积极性。可以说,老早之前就知道什么是重构了,但是总感觉那会的重构就是把整个项目都推翻重来一遍,或许是改变架构,或许是改变设计思路,也或许是业务的改变等等。但是,看完这本书之后,你就不会那么看了。


背景


其实,这本书早就已经下载下来了,一直没有时间到现在看来也的确是一大损失。我觉得,这本书最好是在有过实际经验之后,再看的话,会更加深有体会。


什么是重构


那么,什么才是真正的重构呢?从这本书里可以找到答案。不过,我不打算用书里边的话来说,因为,书中开头部分是没有给出定义的,而是采用了一个经典的小例子加以诠释。而这里,我也不打算直接 copy 作者的例子,而是从我自己的角度来说说什么是重构。

显而易见,重构其实意味着要改变代码,或者说是要重新修改,或者重写代码。当然,他并不是简单的重复工作,这样的重复工作也是没有多大意义的。他的意义就在于,在日常的开发中,通过理解业务需求,捋顺业务逻辑,把繁杂、冗余的代码尽量简化,减少模块之间的耦合。

说到底,真正的重构并不是要等到一个项目的结束,推翻然后重新设计、重新开放。而是在设计之前就要考虑到可能会出现的问题,或者是设计之前借鉴类似的项目。当设计完成之后,转向开发时,编码的过程也是在重构中度过的。开发人员在编码之时,也要考虑到代码的耦合性和功能性。当然,在实际开发中,很多时候是要求进度的,这种情况下很难控制代码的质量,更别说是重构了。其实,这种情况下,是属于快速迭代的产品,每个迭代周期完成之后,还是要有代码评审的,在代码评审时,可以针对具体的代码进行重构,而且,这种方式也有助于知识共享和知识的传播,对于整个团队来说,还是很有必要的。


重构的起点


作为开发人员,其担负着把业务需求、功能描述转换成代码的职责,从抽象的需求转换为具体的、直观的实现。那么,所谓的重构的起点在哪里?应该怎么界定是不是需要重构呢?

在《重构》这本书中,就专门提出并解决了这个问题。其中有单独的一章来说明“代码的坏味道”。那么,就来看看都有什么吧,何种情况下,会需要重构呢?

  • 重复代码(Duplicated Code)
如果你在一个以上的地点看到相同的程序结构,比如说,在一个类中不止一次的用到了同一个方法块,那么可以肯定的是,这个方法(程序结构)已经是重复代码了,你需要设法将它们合而为一,加以提炼。

如果两个毫不相干的类出现重复代码,那么你就要考虑,对其中一个进行简化,将重复代码提炼到一个独立的类中,然后在另一个类中使用这个新类。当然,也可能出现重复代码只应该出现在某个类中,而另外的类则只是引用他。因此,你必须决定这个函数应该放在哪最合适,并确保他被安置后就不会在其他类里出现。

  • 过长函数(Long Method)
拥有短函数的对象会活的比较好、比较长。换句话说,就是更容易维护。我们经常会说一行代码能完成的事,就别让他写两行。这是因为,函数过于长的话,维护起来会很困难,而且理解起来也是很头疼的事。例如,条件表达式和循环常常也需要重新提炼一翻,把这个体积过于庞大的代码块分割成一个新的方法。

  • 过大的类(Large Class)
如果想利用单个类做太多的事情,其内往往就会出现太多的实例变量,一段如此,重复代码也就会接踵而至了。就像“单一职责原则”所提倡的那样,每个类只做一件事,这样类的职责单一了,后期的阅读和维护都是很方面的事。对于扩展性来说,也不是什么难事。

  • 过长参数列(Long Parameter List)
记得刚开始学编程的时候,总是把函数所需要的东西以参数的形式传进去,孰不知,参数越传越多,以后再看代码的时候,都不知道这些参数代表什么,难以理解。而学了面向对象编程之后,有了对象,你就不必把函数需要的所有东西都以参数的形式传递给他了,有时,你只需传递一个对象即可解决问题。

  • 霰弹式修改(Shotgun Surgery)
设计模式中,有一个原则是“对扩展开放,对修改关闭”。但是,在开发过程中,难免会遇到修改代码的时候,虽然不提倡修改,但我们尽量做到最小的修改,也就是只要修改代码的某一处,就能够解决问题。其实,这就是对上边重复代码进行抽象的结果,只有把重复代码提炼出来,才能做到最小的修改。

  • 依恋情结(Feature Envy)
这种问题在于,把方法放在了不合适的类中,例如,某个方法在进行计算的时候,会调用另外一个类的很多个方法,那么你就要考虑,这个方法是不是还有必要放在这个类中,是否可以考虑把该方法进行迁移呢?

  • switch 惊悚现身(Switch Statements)
面向对象程序一个最明显特征就是,少用 Switch 或(case)语句,从本质上说,switch 语句的问题在于重复。你常会发现同样的 switch 语句散布在不同的地点。如果要为他添加一个新的 case 语句,就必须找到所有的 switch 语句并修改他们。而面向对象中多态的出现,则正好解决了这个问题。大多数时候,一看到 switch 语句,你就要考虑用多态来替换他。但如果只是偶尔的一个 switch ,就没有考虑的必要了。

  • 冗赘类(Lazy Class)
你所创建的每一个类,都得有人去理解他、维护他,这些工作都是要花钱的。如果一个类的所得不值得其身价,它就应该消失。开发中经常会遇到这样的情况,由于业务的变更,或者是由于代码的重构,导致原来的类失去了原有的存在价值,那么,就应该去掉它。

  • 令人迷惑的暂时字段(Temporary Field)
很多时候,我们都喜欢设置临时变量,而起名字的方式也超简便,直接叫一个“tmp”或者“temp”等等,看似简单的背后,却存在着不可忽视的隐患。设想一下,你正在维护一个从来没有接触过的项目,而这个项目的大多数类中,都有很多个临时变量,而且他们的变量名都是“temp”类似的东西,你觉得你能理解代码的意思吗?告诉你,看这样的代码,你会发疯的!


结束语


说了这么多,其实仔细想想,这些东西在日常的开发中也都能体会到,只不过有时我们并没有注意过罢了。而且,也有童鞋时不时的会对自己的代码进行优化,使得把大部分的精力都专注在业务开发上,而不是“复制”、“粘贴”重复的代码,因为他们知道,重复的代码只会白白的浪费时间、降低效率。



2 0