当前位置:编程学习 > php >>

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

思维导图
 
点击下图,可以看大图。

 
 介绍
 
我把我比较喜欢的和比较关注的地方写下来和大家分享。上次我写了篇《php 跟老大的对话》。还是有很多疑问,这书帮了我不少的忙。
 
如果你比较繁忙,或者懒得看文字,建议你直接看截图,也会有很大的收获的。你可以通过比较截图中的代码就能知道孰优孰劣了。
 
代码部分我为什么用图呢?因为我经常用手机看代码,博客园的代码在手机里乱七八糟的,还是看图比较舒服。
 
 专业术语
 
我们毕竟是用英文字母编码,所以用一些英语单词,更能显示出我们的专业性。以下的英文单词,你如果掌握了,与其他coder交流的时候会更直接,更专业。——臭显摆一下吧,呵呵。
“*”表示文中经常提到的
 
inline:内联
function:函数
*method:方法
finely grained:细粒度的
rename:重命名
query:查询
temp:临时(temporary)——一般指临时变量
*extract:提取——我个人更喜欢翻译成“提炼”
*duplicate:复制
split:剖解
variable:变量
factor:因素,因子
 
 重构原则
 
一、何谓重构?
    名词形式:对软件内部结构的一种调整,目的是在不改变软件之可察行为前提下,提高其可理解型性,降低其修改成本。
  动词形式:使用一系列重构准则,在不改变软件之可察行为前提下,调整其结构。
 
 二、为何重构?
  1、经常重构可以让代码维持该有的形态。
  2、让代码找到合适的位置。
  3、让软件更易理解。
  4、可以找到bug。
  5、提高我们的编码速度。
 三、重构的难题
  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、条件式和循环常常也是提炼信号。
 
三、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
将这段代码放进一个独立函数中,并让函数名称解释改函数的用途



 
动机:
简短而有良好命名的函数:
  1、函数finely grained,彼此复用机会就比较大。
  2、函数读起来像读一系列comments。
  3、函数覆写容易。
作法:
  1、创建新函数,根据函数的意图命名——以它“做什么”命名,而不是以它“怎样做”命名。
    =》即使Extract Function 非常简单,例如只是消息或函数调用,只要新Function能够以更好方式昭示代码意图,你也应该提炼它。但如果你想不出更有意义的名称,就别动它。
  2、将Extract的代码从Source Function 中Move到New Function中。
二、Inline Method
  Method Body与Method Name一样清晰易懂的时候,请Inline Method。



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



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



 
动机:
  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)。
  
如果代码组织良好,那么你往往能发现更有效的优化方案。————如果性能真的很糟糕,那么放回去也很容易。 www.zzzyk.com
 
五、Introduce Explaining Variable
 
将复杂表达式中(或其中一部分)的结果放进一个临时变量,以此变量名称来解释表达式用途。
 



 
动机:
  表达式复杂而且难以阅读。在这种情况下,临时变量可以帮助你将表达式分解为比较容易管理的形式。
  
 六、Split Temporator Variable
 
 某个临时变量被赋值超过一次,它既不是循环变量,也不是集合变量。那么针对每次赋值,创造一个独立的,对应的临时变量。

 
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,