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 相关文章推荐
在PHP3中实现SESSION的功能(二)
Oct 09 PHP
关于php连接mssql:pdo odbc sql server
Jul 20 PHP
php通过ajax实现双击table修改内容
Apr 28 PHP
PHP自定session保存路径及删除、注销与写入的方法
Nov 18 PHP
php使用Cookie实现和用户会话的方法
Jan 21 PHP
详谈PHP编码转换问题
Jul 28 PHP
Laravel最佳分割路由文件(routes.php)的方式
Aug 04 PHP
php结合md5的加密解密算法实例
Sep 30 PHP
PHP基于imagick扩展实现合成图片的两种方法【附imagick扩展下载】
Nov 14 PHP
PHP ADODB生成HTML表格函数rs2html功能【附错误处理函数用法】
May 29 PHP
thinkPHP框架通过Redis实现增删改查操作的方法详解
May 13 PHP
php创建类并调用的实例方法
Sep 25 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
一个高ai的分页函数和一个url函数
2006/10/09 PHP
优化PHP代码的53条建议
2008/03/27 PHP
php中session退出登陆问题
2014/02/27 PHP
Dwz与thinkphp整合下的数据导出到Excel实例
2014/12/04 PHP
Laravel 简单实现Ajax滚动加载示例
2019/10/22 PHP
Laravel中GraphQL接口请求频率实战记录
2020/09/01 PHP
jquery插件之信息弹出框showInfoDialog(成功/错误/警告/通知/背景遮罩)
2013/01/09 Javascript
JS实现金额转换(将输入的阿拉伯数字)转换成中文的实现代码
2013/09/30 Javascript
深入理解javascript变量声明
2014/11/20 Javascript
arguments对象验证函数的参数是否合法
2015/06/26 Javascript
javascript实现图片轮播效果
2016/01/20 Javascript
AngularJS动态绑定HTML的方法分析
2016/11/07 Javascript
Bootstrap 树控件使用经验分享(图文解说)
2017/11/06 Javascript
初识 Vue.js 中的 *.Vue文件
2017/11/22 Javascript
微信小程序实现点击文字页面跳转功能【附源码下载】
2017/12/12 Javascript
JS实现简单的星期格式转换功能示例
2018/07/23 Javascript
vue 导航内容设置选中状态样式的例子
2019/11/01 Javascript
javascript 关于赋值、浅拷贝、深拷贝的个人理解
2019/11/01 Javascript
Angular8引入百度Echarts进行图表分析的实现代码
2019/11/27 Javascript
vue quill editor 使用富文本添加上传音频功能
2020/01/14 Javascript
js实现右键弹出自定义菜单
2020/09/08 Javascript
Python3访问并下载网页内容的方法
2015/07/28 Python
Python 比较两个数组的元素的异同方法
2017/08/17 Python
Python使用pylab库实现绘制直方图功能示例
2018/06/01 Python
选择Python写网络爬虫的优势和理由
2019/07/07 Python
Django 全局的static和templates的使用详解
2019/07/19 Python
python对常见数据类型的遍历解析
2019/08/27 Python
Python 序列化和反序列化库 MarshMallow 的用法实例代码
2020/02/25 Python
Python3标准库之functools管理函数的工具详解
2020/02/27 Python
PyCharm常用配置和常用插件(小结)
2021/02/06 Python
英国领先的露营和露营车品牌之一:OLPRO
2019/08/06 全球购物
留学推荐信怎么写
2014/01/25 职场文书
2014年党务公开方案
2014/05/08 职场文书
职员竞岗演讲稿
2014/05/14 职场文书
2014年售票员工作总结
2014/11/19 职场文书
WCG2010 星际争霸决赛 Flash vs Goojila 1 星际经典比赛回顾
2022/04/01 星际争霸