Heim >php教程 >php手册 >【转】PHP 杂谈《重构-改善既有代码的设计》之一 重新组织你的函数

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

WBOY
WBOYOriginal
2016-10-18 08:42:031192Durchsuche
原文地址: 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、条件式和循环常常也是提炼信号。
 
  4、《代码整洁之道》的一个例子。我们可以想想!

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

 

动机:

简短而有良好命名的函数:——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。

 

三、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)。

  

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

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

 

 

动机:

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

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

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

 

七、Replace Method with Method Object

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

 

 

动机:

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

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

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

八、Substitute Algorithm
 
如果你想把某个算法替换为另一个更清晰的算法,那么将Method Body替换为另一个算法。——就是直接修改原来的Method Body。
 
动机:随着对问题有了更多的了解,你发现一件事可以有更清晰的方式,就应该以较清晰的方式取代复杂方式。
 
 总结
 
这只是本书的一部分内容,我知道会有很多的coder应该有不同的观点,我自己也是,有的很赞同,有的我也是不太赞同的。所以要“则其善之而从之,其不善之而改之”。
 
欢迎大家发表下自己的看法。

 

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn