《重构-改善既有代码的设计》之一 重新组织你的函数

作者:无名 - 软件应用 -

思维导图

 最近看了(川山甲)的博客,受益匪浅,所有记录下来

http://www.cnblogs.com/baochuan/ (川山甲)博客地址

点击下图,可以看大图。

《重构-改善既有代码的设计》之一 重新组织你的函数_第1张图片

 

 介绍

 

我把我比较喜欢的和比较关注的地方写下来和大家分享。上次我写了篇《php 跟老大的对话》。还是有很多疑问,这书帮了我不少的忙。

 

如果你比较繁忙,或者懒得看文字,建议你直接看截图,也会有很大的收获的。你可以通过比较截图中的代码就能知道孰优孰劣了。

 

代码部分我为什么用图呢?因为我经常用手机看代码,博客园的代码在手机里乱七八糟的,还是看图比较舒服。

 

 专业术语

 

我们毕竟是用英文字母编码,所以用一些英语单词,更能显示出我们的专业性。以下的英文单词,你如果掌握了,与其他coder交流的时候会更直接,更专业。——臭显摆一下吧,呵呵。

“*”表示文中经常提到的

 

inline:内联

function:函数

*method:方法

finely grained:细粒度的

rename:重命名

query:查询

temp:临时(temporary)——一般指临时变量

*extract:提取——我个人更喜欢翻译成“提炼”

*duplicate:复制

split:剖解

variable:变量

factor:因素,因子

 

  1、提炼方法(extract method)

  2、内联方法(inline method)

  3、内联变量(一个临时变量,只被一个简单表达式赋值一次,而且赋值完也只使用了一次)

  4、用查询代替变量(如果一个Temp变量,保存一个表达式,将这个表达式Extract Method)

  5、解释变量(将复杂表达式中(或其中一部分)的结果放进一个临时变量,以此变量名称来      解释表达式用途。)

  6、分离变量(某个临时变量被赋值超过一次,它既不是循环变量,也不是集合变量。那么针对每次赋值,创造一个独立的,对应的临时变量。)

  7、类代替方法(某个临时变量被赋值超过一次,它既不是循环变量,也不是集合变量。那么针对每次赋值,创造一个独立的,对应的临时变量。)

 

 重构原则

 

一、何谓重构?

     名词形式:对软件内部结构的一种调整,目的是在不改变软件之可察行为前提下,提高其可理解型性,降低其修改成本。

  动词形式:使用一系列重构准则,在不改变软件之可察行为前提下,调整其结构。

 

 二、为何重构 ?

  1、经常重构可以让代码维持该有的形态。

  2、让代码找到合适的位置。

  3、让软件更易理解。

  4、可以找到bug。

  5、提高我们的编码速度。

《重构-改善既有代码的设计》之一 重新组织你的函数_第2张图片

 三、重构的难题

  1、修改接口命名

    如果你的类中的方法是public,那么你在rename的时候,冒着很大的风险,你不知道到底有哪些模块在调用你的这个方法(我们经常的做法是在整个项目下做grep操作,然后逐一看各个模块的调用和逻辑)。——所以我们在编写类的时候不管是属性还是方法尽量做到private,避免接口开放。

 

  2、何时不该重构

    (1)重写所有代码,而且现有代码实在太混乱,重构还不如重写。

    (2)项目临近结束的时候,应该避免重构。我们可以把重构放到二期去解决。 

 

 代码的坏味道

  一、Duplicate Code

  1、同一个类,两个方法含有相同表达式。

    解决方法:你可以Extract Method提炼重复代码,然后让这两个方法都调用这个Extract Method。

       2、两个类,有相似的方法。

     解决方法:(1)把两个类的方法提出来,共同构造一个父类。

             (2)把其中一个类的方法删除,调用另一个类的方法。

 二、Long Method

  1、短函数:代码阅读费点力气,因为我们必须经常转换上下文去看看子程序做了什么。但是让small method容易理解的真正关键在于一个好的名字。读者可以通过名字了解函数的作用,根本不必去看其中写了些什么。—— 早期的编程语言中,调用方法需要额外开销,这使得coder不愿意使用small method。但是现代的OO语言几乎已经完全免除了process内的额外开销(函数调用)。

 

  2、注释地方提炼信号:每当感觉需要以注释来说明点什么的时候,我们就把需要说明的东西写进一个独立函数中,并以其用途命名。可以对一组或甚至短短一行代码做这件事。——只要函数名称能够解释其用户,我们也该毫不犹豫地那么做。

 

"函数"理解为”做什么“或”如何做“

 

  3、条件式和循环常常也是提炼信号。

 

  4、《代码整洁之道》的一个例子。我们可以想想!

《重构-改善既有代码的设计》之一 重新组织你的函数_第3张图片

 

三、Large Class

 

  1、Class内数个属性变量有相同前缀或者字尾,可使用Extract Class。

 

  2、Class内并非大多数变量使用属性变量,可使用Extract Class。

  

  3、有太多代码,可Extract Class。

 

四、Long Parameter

  做成Introduce Parameter Object。——这个我不太赞同,因为我在使用别人方法的时候,我很少去看代码实践,更不要说去看里面都用到了对象的那些属性或者方法,取我想要的数据了。

 

五、Switch Statements

  1、少用switch语句。——问题在于duplication。添加新case的时候,你必须找到所有case并修改它们。

  

  2、用多态来替换它。做法:1.将switch进行Extract Method;2.MoveMethod把case里的实践代码放到多态性的class里。

 

六、 Comments

  试试用Extract Method,如果还不行,那你试试Rename Method。

 

当你感觉需要撰写注释,请先尝试重构,试着让所有注释变得多余。

 

  注释一般用于将来的打算,还可以用于你并无十足把握的区域(为什么做某事)。

  

 重新组织你的函数

 

  Long Method往往包含太多信息,这些信息又被错综复杂的逻辑掩盖,不易鉴别。

 

一、Extract Method

状况:我看见一个过长的函数或者需要一段注释才能让人理解用途的代码,那么将这段代码放进一个独立函数中,并让函数名称解释改函数的用途。

《重构-改善既有代码的设计》之一 重新组织你的函数_第4张图片

《重构-改善既有代码的设计》之一 重新组织你的函数_第5张图片

 

动机:

简短而有良好命名的函数:——finely grained

  1、复用机会大。

  2、函数读起来像读一系列comments。

  3、函数覆写容易。

重点:函数长度关键在于函数名称和函数本体之间的语义距离。如果提炼动作可以强化代码的清晰度,那么就去做。

作法:

  1、创建新函数,根据函数的意图命名——以它“做什么”命名,而不是以它“怎样做”命名。

    =》 即使Extract Function 非常简单,例如只是消息或函数调用,只要新Function能够以更好方式昭示代码意图,你也应该提炼它。但如果你想不出更有意义的名称,就别动它。

  2、将Extract的代码从Source Function 中Move到New Function中。

二、Inline Method

  Method Body与Method Name一样清晰易懂的时候,请Inline Method。

《重构-改善既有代码的设计》之一 重新组织你的函数_第6张图片

《重构-改善既有代码的设计》之一 重新组织你的函数_第7张图片

 

三、Inline Temp

一个临时变量,只被一个简单表达式赋值一次,而且赋值完也只使用了一次。——请Inline Temp

《重构-改善既有代码的设计》之一 重新组织你的函数_第8张图片

《重构-改善既有代码的设计》之一 重新组织你的函数_第9张图片

 

四、Replace Temp with Query

如果一个Temp变量,保存一个表达式,将这个表达式Extract Method。——这就是所谓的查询式,query

《重构-改善既有代码的设计》之一 重新组织你的函数_第10张图片

《重构-改善既有代码的设计》之一 重新组织你的函数_第11张图片

 

动机:

  1、局部变量会使代码难以提炼。

  2、临时变量会驱使你写出更长的代码。如果改成query method,那么class下的method,都可以获得这份信息。——将编写出更清晰的代码。

  3、Replace Temp with Query往往是你运用Extract Method之前必不可少的步骤。

作法:

  1、找出只被赋值一次的临时变量。

    =>  如果临时变量赋值超过一次,考虑使用Split Temporary Variable将它分割成多个变量。

  2、对Temp Variable赋值的右侧部分,Extract到一个独立函数中。

           =>  将Method声明为private,日后如果有其他class用的时候再放开它(public或protected)。

  

如果代码组织良好,那么你往往能发现更有效的优化方案。————如果性能真的很糟糕,那么放回去也很容易。

 

五、Introduce Explaining Variable

 

将复杂表达式中(或其中一部分)的结果放进一个临时变量,以此变量名称来解释表达式用途。

 

《重构-改善既有代码的设计》之一 重新组织你的函数_第12张图片

《重构-改善既有代码的设计》之一 重新组织你的函数_第13张图片

 

动机:

  表达式复杂而且难以阅读。在这种情况下,临时变量可以帮助你将表达式分解为比较容易管理的形式。

  

 六、Split Temporator Variable

 

 某个临时变量被赋值超过一次,它既不是循环变量,也不是集合变量。那么 针对每次赋值,创造一个独立的,对应的临时变量。

《重构-改善既有代码的设计》之一 重新组织你的函数_第14张图片

 

《重构-改善既有代码的设计》之一 重新组织你的函数_第15张图片

 

动机:

  1、如果临时变量承担多个责任,它就应该被替换为多个临时变量。每个变量只承担一个责任。

  2、同一个临时变量承担两件不同的事情,会令review变得糊涂。

六、Remove Assignments To Parameters

如果你的代码对参数进行赋值,那么 以一个临时变量取代该参数的位置

 

《重构-改善既有代码的设计》之一 重新组织你的函数_第16张图片

《重构-改善既有代码的设计》之一 重新组织你的函数_第17张图片

 

七、Replace Method with Method Object

大型函数对局部变量的使用无法采用Extract Method。那么将这个Method放进一个单独对象中,如此一来,让局部变量成为对象的filed,然后在同一个对象中将大型函数分解为数个小型Method。

 

《重构-改善既有代码的设计》之一 重新组织你的函数_第18张图片

 

《重构-改善既有代码的设计》之一 重新组织你的函数_第19张图片

动机:

  1、将相对独立的代码从大型Method中Extract出来,就可以大大提高代码的可读性。

  2、一个Method中,局部变量泛滥成灾,分解这个函数将会非常困难。

  3、Replace Method with Method Object 会将所有局部变量变成对象的值域。然后对这个新对象进行Extract Method了。

八、Substitute Algorithm

 

如果你想把某个算法替换为另一个更清晰的算法,那么 将Method Body替换为另一个算法。——就是直接修改原来的Method Body。

 

动机:随着对问题有了更多的了解,你发现一件事可以有更清晰的方式,就应该以较清晰的方式取代复杂方式。

 

 总结

 

这只是本书的一部分内容,我知道会有很多的coder应该有不同的观点,我自己也是,有的很赞同,有的我也是不太赞同的。所以要“则其善之而从之,其不善之而改之”。

 

欢迎大家发表下自己的看法。

IT人知识库 原文链接:http://www.itpeo.net/15315/3488223.html





rfedfre

EJB基于RMI, 真理还是谎言?

很早以前就听高手说过EJB基于RMI, 最近也有美国同事说基于RMI的EJB远程调用会有问题。 but, 看了一些... ...

rfedfre

NAT与NAT穿越学习总结

1、引言 网络地址转换(Network Address Translation,简称NAT)是一种在IP分组通过路由器... ...

rfedfre

Memcached Java客户端2.6.1发布

Memcached是被广泛使用的分布式缓存技术。不同的语言有不同的Memcached客户端程序,对于Java客户端来说,... ...

rfedfre

Users’ Choice: Application Server Rankings-09/2008

Users’ Choice: Application Server Rankings - September 20... ...

rfedfre

利用WSAD XDE建立数据库模型(uml)

一:Uml基础知识(uml主要包括实体,关系和图) 1.关系:包括依赖(一种使用关系,一个量的变化会影响另一个量) ... ...

rfedfre

JavaEE复习

老师给的复习题。下周考试。仅供参考。 一、选择题 第1题.编写一个Filter,需() A.继承Fil... ...

rfedfre

One Note of Head first design patterns (Strategy pattern)

Today ,I read the chapter one of the Head first design patte... ...

rfedfre

linux单向免密码登录

首先关闭防火墙:http://wenwang.iteye.com/admin/blogs/2229975 &n... ...

rfedfre

关于BAE中SVN提交失败的原因分析

SVN提交失败且提示的错误信息包含:“Access to ………… forbidden”,则出错的原因可能有: 1. ... ...

rfedfre

sql时间比较查询当前时间的数据,前一条,后一条

select top 1 * from CheckBill where datediff(second,'2011-0... ...

rfedfre

项目管理过程

一、项目启动1、启动过程的目的是: (1)建立并定义项目的目的和目标(具体、可度量、有时间限制) (... ...

rfedfre

JAVA之 IO流

一、IO流流就是字节序列的抽象概念,能被连续读取数据的数据源和能被连续写入数据的接收端就是流,流机制是Jav... ...

rfedfre

Eclipse 下调试Tomcat6源码

    近期对 Tomcat 的一些原理机制产生了兴趣,于是便下载源码进行 DEBUG 来... ...

rfedfre

300万条记录 like 和 charindex 函数性能比较

300万条记录 like 和 charindex 函数性能比较 环境:sql2005 数据量:300万 查询结... ...

rfedfre

Webwork Result失效的一个错误

访问Action.不能跳转到指定的jsp页面,有如下异常 java.lang.NoSuchMethodExceptio... ...

CSS 图片拼接技术

对于拼接图片的显示,无论是作为背景图使用,还是作为前景图使用,都可以使用CSS完全控制。 下面就以显示以下拼接图片... ...