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


Posted in PHP onApril 09, 2012

思维导图 点击下图,可以看大图。 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、《代码整洁之道》的一个例子。我们可以想想!

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

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

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

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

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

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

 

动机:

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

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

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

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

 

三、Inline Temp

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

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

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

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

 

四、Replace Temp with Query

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

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

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

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

 

动机:

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

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

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

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

 
动机:

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

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

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

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

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

 

动机:

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

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

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

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

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

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

 

七、Replace Method with Method Object

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

 

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

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

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

动机:

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

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

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

八、Substitute Algorithm
 
如果你想把某个算法替换为另一个更清晰的算法,那么将Method Body替换为另一个算法。——就是直接修改原来的Method Body。
 
动机:随着对问题有了更多的了解,你发现一件事可以有更清晰的方式,就应该以较清晰的方式取代复杂方式。

总结

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

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

PHP 相关文章推荐
在windows iis5下安装php4.0+mysql之我见
Oct 09 PHP
WindowsXP中快速配置Apache+PHP5+Mysql
Jun 05 PHP
php 带逗号千位符数字的处理方法
Jan 10 PHP
php笔记之:数据类型与常量的使用分析
May 14 PHP
使用URL传输SESSION信息
Jul 14 PHP
Yii2 rbac权限控制操作步骤实例教程
Apr 29 PHP
常用PHP封装分页工具类
Jan 14 PHP
php 猴子摘桃的算法
Jun 20 PHP
PHP错误处理函数register_shutdown_function使用示例
Jul 03 PHP
关于php支持的协议与封装协议总结(推荐)
Nov 17 PHP
PHP实现的ID混淆算法类与用法示例
Aug 10 PHP
Laravel使用RabbitMQ的方法示例
Jun 18 PHP
PHP乱码问题,UTF-8乱码常见问题小结
Apr 09 #PHP
PHP中return 和 exit 、break和contiue 区别与用法
Apr 09 #PHP
php 的加密函数 md5,crypt,base64_encode 等使用介绍
Apr 09 #PHP
PHP压缩html网页代码(清除空格,换行符,制表符,注释标记)
Apr 02 #PHP
PHP文件注释标记及规范小结
Apr 01 #PHP
用PHP读取超大文件的实例代码
Apr 01 #PHP
PHP新手用的Insert和Update语句构造类
Mar 31 #PHP
You might like
php array的学习笔记
2012/05/16 PHP
PHP生成sitemap.xml地图函数
2013/11/13 PHP
PHP+jquery+ajax实现即时聊天功能实例
2014/12/23 PHP
php注册和登录界面的实现案例(推荐)
2016/10/24 PHP
Laravel 修改验证异常的响应格式实例代码详解
2020/05/25 PHP
一个很简单的办法实现TD的加亮效果.
2006/06/29 Javascript
window.parent与window.openner区别介绍
2012/04/12 Javascript
js之onload事件的一点使用心得
2013/08/14 Javascript
Javascript实现的常用算法(如冒泡、快速、鸽巢、奇偶等)
2014/04/29 Javascript
JavaScript中获取鼠标位置相关属性总结
2014/10/11 Javascript
jquery使用remove()方法删除指定class子元素
2015/03/26 Javascript
javascript等号运算符使用详解
2015/04/16 Javascript
javascript实现框架高度随内容改变的方法
2015/07/23 Javascript
Bootstrap导航栏各元素操作方法(表单、按钮、文本)
2015/12/28 Javascript
Javascript中this绑定的3种方法与比较
2016/10/13 Javascript
node.js与C语言 实现遍历文件夹下最大的文件,并输出路径,大小
2017/01/20 Javascript
vue的无缝滚动组件vue-seamless-scroll实例
2017/12/18 Javascript
Nuxt.js实战和配置详解
2019/08/05 Javascript
jquery 键盘事件 keypress() keydown() keyup()用法总结
2019/10/23 jQuery
vue 实现单选框设置默认选中值
2019/11/07 Javascript
jquery实现弹窗(系统提示框)效果
2019/12/10 jQuery
浅谈Vue 函数式组件的使用技巧
2020/06/16 Javascript
pymongo实现多结果进行多列排序的方法
2015/05/16 Python
基于Python的接口测试框架实例
2016/11/04 Python
python利用拉链法实现字典方法示例
2017/03/25 Python
Python决策树和随机森林算法实例详解
2018/01/30 Python
Python实现模拟浏览器请求及会话保持操作示例
2018/07/30 Python
python scatter函数用法实例详解
2020/02/11 Python
Django 再谈一谈json序列化
2020/03/16 Python
keras实现多种分类网络的方式
2020/06/11 Python
python中return不返回值的问题解析
2020/07/22 Python
Html5页面二次分享的实现
2018/07/30 HTML / CSS
database面试题
2013/03/28 面试题
办公室主任先进事迹
2014/01/18 职场文书
人力资源管理求职信
2014/08/07 职场文书
营运督导岗位职责
2015/04/10 职场文书