重构代码 01

来源:互联网 发布:简单网络爬虫工具 编辑:程序博客网 时间:2024/05/21 14:55

1.介绍

传统的观念是先设计,然后进行写代码。但是最初的设计往往都并不是完美和尽然的,重构显得非常必要。重构所强调的就是在写代码的过程中再不断地进行设计和修改,从而达到最终的设计,即使最初的设计很混乱也没有关系。有可能一小段代码本身没什么可改的,但是如果是在一个大项目中的话,就有改的必要了。

首先,你的方法代码不能太长了,一旦代码太长了,系统要进行修改的时候就很难修改,因为到时候你也不知道该改哪里。还有,太长的代码往往很难重新使用,因为涵盖的逻辑太多,涉及的类太多,一改通常就基本上全部要修改。记住以前听说的一个规则,方法不要超过15行。千万不要使用代码拷贝,因为你一旦拷贝了代码,遇到要修改,你需要改的地方就增加了,出错的几率也就增加了。

当你写了一段代码之后,最好就进行一个测试,因为是人总会犯错误。测试完了再进行下一步,这样才能保证代码的可靠性,也少了后期的烦恼。测试代码要做到让代码自己进行检查,而不是人为地去进行,这样会花费很多时间,而且也容易出错。千万别觉得写测试浪费时间,这个是值得花时间的,谨记这一点。在进行代码重构之前,记住先要确保你有一系列的test,尽量想一想可能发生的各种情况,而且这些test都必须是self-checking的。

定义变量,参数和方法的时候,对其名字进行深思熟虑,这样可以让你的代码逻辑更加清晰,要做到别人能读懂你的代码。

尽可能地去掉临时变量,通常,如果有方法可以获取临时变量的话,就去掉它。这种情况往往是和循环有关,这个时候你原先的一个循环如果拆成多个方法就可能变成了多个循环。需要考虑一个问题,那就是原先的一个循环肯定大于分拆后的任何一个循环的时间,如果分拆的循环不一定使用的话,多个还是要划算一些。还有就是,即使是方法的话,只要是在这个类中,那么大家都可以调用,更别说public方法了。尽量避免多重循环。

如果你要通过对某个属性判断而得出一定的结论,那么最好将该方法写在那个属性所在的类中。


2.什么叫重构

为了让软件更加容易理解并且不用修改其可见的功能就能使得维护更加容易,从而对软件的内部结构进行的更改。

 可能需要长达几个小时的时间进行整个的重构,在这个过程中你需要不断地进行小范围的重构。

需要尤其值得注意的是: 软件的接口功能绝对不能改。

一句话,就是重构其实就是引入了更多的间接性到程序中。将大的尽可能的变小,虽然变多了,但是也就更加灵活了。但是,它同时也是双刃剑,东西变得太多了以后,也很难进行维护,可读性也许也随之变得很差。所以,一句话,在保证块的数量最少的前提下,放手去将大的变小。


3.为什么要进行重构

如果代码设计得很烂的话,做同样的事情往往要多写很多代码。很大的原因就是很多地方都有同样功能的代码。改善设计的一个重要的方面就是尽可能地去掉重复的代码。但是记住,减少代码的数量(功能相同的话),基本上并不会使得代码整体运行速度大幅提升。但是,代码量减少了以后,对于以后的修改大有好处,因为如果重复代码少的话(假设理想状况下完全没有重复代码,任何东西出错了都只需要改一次),需要修改的地方就少了。如果消除了重复代码,那么你就可以保证任何一段代码都只表达一次,并且一次就说清楚了。

还有一个非常重要的原因就是,你的代码往往是需要给别人看和修改的。如果别人能更好地理解你的代码,那么进行修改,添加就更加迅速。其实电脑本身根本无所谓,多编译一会儿并不影响任何性能。重构可以让代码更具有可读性,这样的话,别人使用起来更加方便,整体的工作效率也就提高了。

尽可能少的去专门记代码,如果你在看你自己的代码的时候,感觉有些理解不能,这个时候可能就要考虑重构了,持续这样进行,你自己就不用专门去记自己写的代码,而只是进行简单的查找就能知道代码的用途,逻辑等等。当然,用久了自己就能记住。更加重要的是,一旦你把一些逻辑理得更加清楚以后,你对编程本身认识的高度会不断地上升。

还有,可以帮助你发现bugs。一旦逻辑清晰了,一些问题也就自然而然地暴露出来了。

最后,所有之前说的,都是为了达到这样一个目标: 使得你编程的速度更快。按理说,找重复代码,重构,写测试和运行测试都会降低编程效率,但是为什么会提高效率呢?其实,还是那样说,和写unit test一样,写的时候当然觉得浪费时间,没事也就算了,但是一旦要是遇上有事了,多余的时间就搭进去了。代码要是设计得好,从长远来看,肯定是 节约时间的。代码设计得差的话,你要花时间去理解代码,而且有些代码无法进行重用,你又得重新写,时间被就耽误了。


4.什么时候进行重构

其实并不需要专门抽出时间,然后说我要专门花2天的时间来重构代码,重构应该是时时刻刻在发生的。并不是说,你要计划重构,而是说你想做点其它的事情,重构刚好可以帮助你做起来更加方便。记住3条规则:第一条,当你想做一件事情的时候,你尽管放手去做就是了; 第二条,当你再次做类似的事情的时候,没关系,继续做,但是你必须警惕,告诉自己这个东西已经写了2遍了; 第三条,如果第三次出现,那你就该重构了。

当你添加方法的时候,往往是重构最频繁发生的时候。在已经写成型的代码中添加方法,往往这个方法的功能的一部分已经在别处实现了。或者换句话说,就是你要添加的方法可能对你原先的代码有用。只要你一旦觉得重构可以让代码更容易被理解,马上就动手。

还有一个重构的动机,就是我想加一个东西,比如一个方法,但是发现非常不好加。那么就要考虑重构了,这样将来再想添加东西的时候,也要方便一些。

回顾代码的时候(首先必须说明,这是一个非常好的团队习惯),可以进行重构。大家都可以贡献自己的idea,毕竟每个人都有独到的见解。同时,有经验的程序员可以将自己的思路传达给欠缺经验的同志们。

记住,今天能做的事情今天做完了,但是明天要做的事情做不完的话,还是失败的。所以总的来说做事情要考虑将来,在有可能的情况下,注意代码质量,而不是盲目的按照schedule来。manager当然希望你以最快的方式来完成任务,记住,重构确实能让你做事的效率提高,从而最快地完成任务。


5.重构可能带来的问题

很难说,但是Database就是一个问题多发领域。往往数据库都很难改。

还有就是Interface,接口一旦改了,相关的类,还有用户的接口都会变,不小心会造成很多问题。如果是自己的代码,比如你改了一个interface的方法名称,你可以去把所有调用了这个方法的地方的名字都改了就是,除了稍微麻烦一点之外没什么。但是,一旦你的Interface已经publish了,这就麻烦了,你改不了,因为别人在用,你不知道谁在用。所以,当你必须要改一个接口的时候,你必须把旧的也留着,让旧的调用新的。


6.那些代码有问题?

a.duplicate code,像上面说过的,重复的代码。

b.long method,也是上面说的,过于长的方法,记住15行原则。虽然未必都必须卡在15行这个标准,但是提醒自己不要太长。

c.large class,当一个类想要做太多事情的时候,就会出现太多的成员变量。一旦一个类有太多的成员变量,那么出现重复代码就不远了。如果太多的话,最好就是将相关的成员变量提取出来,重新写一个新的类,避免一个类里面太多东西。搞清楚client想要怎样使用这些类和接口,然后决定怎样进行细分。

d.long parameter list,尝试传递一个对象作为参数比传递一长串的参数要好得多。要是传对象,需要什么就拿什么,不需要的就可以不管。要是传参数,需求增加或者减少,就会一直加加减减,很麻烦。

e.divergent change,如果你觉得你只要一改某个东西就会引起某一个类的3,4处改动,那么最好有2个对象。

f.shotgun surgery,一个改变会引起很多类的改变,那么最好将这些改变都放在一个类中。move method,move field

g.feature envy,意思就是,一个类的方法往往喜欢用到的不是自己所在类的变量,反而是其它类的变量,如果这种情况总是出现的话,就把这个方move到那个类中去。

h.data clumps,就是说应该避免成员变量的list和参数的list。

i.primitive obsession,不太明白

j.switch statements,凡是看到switch语句,就应该立刻想到多态,也不太清楚

还有很多这样的名词,反正都是各种觉得代码可能不合理的地方。但是,个人认为,这个真还得看经验,也得看代码的实际情况。有一点关于comments的,就是说是这样的,写comments本身是非常好的,但是用辩证的观点来看就是,你的代码写得越是清晰,需要的comments往往就越少,所以说当你发现你不得不依赖comments来让别人读懂你的代码的时候,你就要考虑重构了,到最后最理想的结果就是comments反而变得有点多余了。


重构的时候力求进行最小的改动然后立刻进行测试,通过以后再进行下一步。如果你的改动稍微大并且出错了,那么返回原来的代码,然后选择比较小的范围进行改动。