重构技术邱百超badqiu(a)gmail.com讲解内容重构介绍重构原则代码的坏味道重构技巧重构工具使用实例Q&A名言任何一个傻瓜都能写出计算机可以理解的程序,只有写出人类容易理解的程序才是优秀的程序员–MartinFowler什么是重构Refactoring是对软件内部结构的一种调整,目的是在不改变外部行为的前提下,提高其可理解性,降低其修改成本。为什么重构改进软件的设计。程序员对代码所做的为了满足短期利益代码改动,或再没有完全清楚增个架构下的改动,都很容易是代码失去它的清晰结构,偏离需求或设计。而这些改动的积累很容易使代码偏离它原先设计的初衷而变得不可立即和无法维护。Refactoring则帮助重新组织代码,重新清晰的体现结构和进一步改进设计。为什么重构提高代码质量,更易被理解容易理解的代码可以很容易的维护和做进一步的开发。即使对写这些代码的程序员本身,容易理解代码也可以帮助容易地做修改。程序代码也是文档。而代码首先是写给人看的,让后才是给计算机看的。为什么重构Refactoring帮助尽早的发现错(Bugs)Refactoring是一个codereview和反馈的过程。在另一个时段重新审视自己或别人代码,可以更容易的发现问题和加深对代码的理解。Refactoring是一个良好的软件开发习惯。为什么重构Refactoring可以提高开发速度Refactoring对设计和代码的改进,都可以有效的提高开发速度。好的设计和代码质量实体提高开发速度的关键。在一个有缺陷的设计和混乱代码基础上的开发,即使表面上进度较快,但本质是试延后对设计缺陷的发现和对错误的修改,也就是延后了开发风险,最终要在开发的后期付出更多的时间和代价。项目的维护成本远高于开发成本.何时重构?添加新功能时一并重构为了增加一个新的功能,程序员需要首先读懂现有的代码。修补错误时一并重构为了修复一个Bug,程序员需要读懂现有的代码。CodeReview时一并重构何时不该重构?代码太混乱,设计完全错误。与其Refactor,不如重写。明天是DeadLine永远不要做Last-Minute-Change。推迟Refactoring,但不可以忽略,即使进入Production的代码都正确的运行。Refactoring的工作量显著的影响最后期限一个Task的计划是3天,如果为了Refactoring,需要更多的时间(2天或更多)。推迟Refactoring,同步可以忽略。可以把这个Refactoring作为一个新的Task,或者安排在Refactoring的Iteration中完成。两顶帽子[重构]与[添加新功能]添加新功能时,你不应该修改既有代码,只管添加新功能。重构时你就不能再添加功能,只管改进程序结构。此外你不应该添加任何测试(除非发现有先前遗漏的东西)两顶“帽子”可同时进行,一会重构,一会添加新功能。重构与设计重构可以从很大程度上去扶助设计,通常情况下我们的设计不是能贯穿我们软件开发的全过程的,在这个过程中,我们的需求变更的可能性非常大,当需求变了,设计也得变,但是我们已有的实现怎么办?全部废除?显然不能!这时候就要依靠重构来解决这种矛盾。重构与性能关于重构,有一个常被提出的问题:它对程序的性能将造成怎样的影响?为了让软件易于理解,你常会作出一些使程序运行变慢的修改。这是个重要的问题。我并不赞成为了提高设计的纯洁性或把希望寄托于更快的硬件身上,而忽略了程序性能。已经有很多软件因为速度太慢而被用户拒绝,日益提高的机器速度亦只不过略微放宽了速度方面的限制而已。但是,换个角度说,虽然重构必然会使软件运行更慢,但它也使软件的性能优化更易进行。关键在于自己的理解,当你拥有了重构的经验,你也就有能力在重构的基础上来改进程序的性能。重构与模式那么真正要实现重构时,我们有哪些具体的方法呢?可以这样说,重构的准则由很多条,见《重构》这本书。但它不是最终的标准,因为你要是完全按照它的标准来执行,那你也就等于不会重构,重构是一种武器,而真正运用武器的高手是没有武器胜有武器。只有根据实际的需要,凭借一定的思想,才能实现符合实际的重构,我们不能被一些固定的模式套牢了,这样你的程序会很僵化。究竟如何把握这个度,需要大家去总结。重构与思想要想实现一个好的重构,不是重构本身,而是我们在写代码的时候,思想当中时刻有它的位置存在!非常重要!如果你本身就没想着要去重构,那么就是有再好的模式供你调用又怎么样?就是有了好的模式,你不能根据实际的需要去融会贯通,那你做出来的重构有意义么?应用范围代码重构网页重构设计重构...Refactoring的流程流程1读懂代码(包括测试例子代码)Refactoring运行所有的UnitTests流程2读懂代码应用重构工具进行重构(如Eclipse)代码坏味道重复的代码(DuplicatedCode)过长的函数(LongMethod)过大类(LargeClass)过长的参数列(LongParameterList)发散式变化(DivergentChange)霰弹式修改(ShotgunSurgery)依恋情结(FeatureEnvy)数据泥团(DataClumps)基本型别偏执(PrimitiveObsession)Switch语句(SwtichStatements)平行继承体系(ParallelInheritanceHierarchies)冗赘类(LazyClass)夸夸其谈未来性(SpeculativeGenerality)令人迷惑的暂时值域(TemporaryField)过度遇合的消息链(MessageChains)中间转手人(MiddleMan)狎昵关系(InappropriateIntimacy)异曲同工的类(AlternativeClasseswithDifferentInterfaces)不完善的程序库类(IncompleteLibraryClass)纯粹的数据类(DataClass)被拒绝的遗赠(RefusedBequest)过多的注释(Comments)重构技巧重新组织你的函数在对象之间搬移特性重新组织数据简化条件表达式简化函数调用处理概括关系重新组织你的函数ExtractMethods(提炼函数1)Stringname=request.getParameter(Name);if(name!=null&&name.length()0){......}Stringage=request.getParameter(Age);if(age!=null&&age.length()0){......}Stringname=request.getParameter(Name);if(!isNullOrEmpty(name)){......}Stringage=request.getParameter(Age);if(!isNullOrEmpty(age)){......}privatebooleanisNullOrEmpty(finalStringstring){if(string!=null&&string.length()0){returntrue;}else{returnfalse;}}ExtractMethods(提炼函数2:清除注释)voidprintOwing(){//printbannerSystem.out.println(“*********”);System.out.println(“Banner”);System.out.println(“*********”);//printdetailsSystem.out.println(name:+_name);System.out.println(amount+getOutstanding());}voidprintOwing(){printBanner();printDetails(getOutstanding());}voidprintBanner(){System.out.println(“*********”);System.out.println(“Banner”);System.out.println(“*********”);}voidprintDetails(doubleoutstanding){System.out.println(name:+_name);System.out.println(amount+outstanding);}InlineMethod(将函数内联化)InlineTemp(将临时变量内联化)ReplaceTempwithQuery(以查询取代临时变量)doublebasePrice=_quantity*_itemPrice;if(basePrice1000)returnbasePrice*0.95;elsereturnbasePrice*0.98;if(basePrice()1000)returnbasePrice()*0.95;elsereturnbasePrice()*0.98;...doublebasePrice(){return_quantity*_itemPrice;}IntroduceExplainingVariable(引入解释性变量)booleanisMacOs=platform.toUpperCase().indexOf(MAC)-1;booleanisIEBrowser=browser.toUpperCase().indexOf(IE)-1;booleanwasResized=resize0;if(isMacOs&&isIEBrowser&&wasInitialized()&&wasResized){//dosomething}if((platform.toUpperCase().indexOf(MAC)-1)&&(browser.toUpperCase().indexOf(IE)-1)&&wasInitialized()&&resize0){//dosomething}SplitTemporaryVariable(剖解临时变量)doubletemp=2*(_height+_width);System.out.println(temp);temp=_height*_width;System.out.println(temp);doubleperimeter=2*(_height+_width);System.out.println(perimeter);doublearea=_height*_width;System.out.println(area);RemoveAssignmentstoParameters(移除对参数的赋值)ReplaceMethodwithMethodObject(以函数对象取代函数)SubstituteAlgorithm(替换算法)ReplaceNestedConditionalwithGuardClausesdoublegetPayAmount(){doubleresult;if(_isDead)result=deadAmount();else{if(_isSeparated)result=separatedAmount();else{if(_isRetired)result=retiredAmount();elseresult=normalPayAmount();};}returnresult;};doublegetPayAmount(){if(_isDead)returndeadAmount();if(_isSeparated)returnseparatedAmount();if(_isRetired)returnretiredAmount();returnnormalPayAmount();};SplitLoop-1v