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 相关文章推荐
php之XML转数组函数的详解
Jun 07 PHP
用 Composer构建自己的 PHP 框架之构建路由
Oct 30 PHP
php模仿asp Application对象在线人数统计实现方法
Jan 04 PHP
php编写批量生成不重复的卡号密码代码
May 14 PHP
PHP cURL初始化和执行方法入门级代码
May 28 PHP
php计算多维数组中所有值总和的方法
Jun 24 PHP
WordPress主题中添加文章列表页页码导航的PHP代码实例
Dec 22 PHP
Laravel4中的Validator验证扩展用法详解
Jul 26 PHP
php获取微信共享收货地址的方法
Dec 21 PHP
PHP ADODB实现分页功能简单示例
May 25 PHP
Laravel框架实现超简单的分页效果示例
Feb 08 PHP
PHP将整数数字转换为罗马数字实例分享
Mar 17 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读取CURL模拟登录时生成Cookie文件的方法
2014/11/04 PHP
WordPress过滤垃圾评论的几种主要方法小结
2016/07/11 PHP
CI框架实现优化文件上传及多文件上传的方法
2017/01/04 PHP
基于逻辑运算的简单权限系统(实现) JS 版
2007/03/24 Javascript
深入理解JavaScript系列(1) 编写高质量JavaScript代码的基本要点
2012/01/15 Javascript
JS不能跨域借助jquery获取IP地址的方法
2014/08/20 Javascript
JavaScript实现简单获取当前网页网址的方法
2015/11/09 Javascript
详解页面滚动值scrollTop在FireFox与Chrome浏览器间的兼容问题
2015/12/03 Javascript
浅谈angular2的http请求返回结果的subcribe注意事项
2017/03/01 Javascript
Vue 组件间的样式冲突污染
2017/08/31 Javascript
解析Vue 2.5的Diff算法
2017/11/28 Javascript
解决easyui日期时间框ie的兼容的问题
2018/03/01 Javascript
妙用缓存调用链实现JS方法的重载
2018/04/30 Javascript
Angular5中调用第三方库及jQuery的添加的方法
2018/06/07 jQuery
Vue 实现前进刷新后退不刷新的效果
2019/06/14 Javascript
vue中通过使用$attrs实现组件之间的数据传递功能
2019/09/01 Javascript
axios 实现post请求时把对象obj数据转为formdata
2019/10/31 Javascript
微信小程序 scroll-view 实现锚点跳转功能
2019/12/12 Javascript
js观察者模式的弹幕案例
2020/11/23 Javascript
Python标准库urllib2的一些使用细节总结
2015/03/16 Python
pygame学习笔记(1):矩形、圆型画图实例
2015/04/15 Python
Python按行读取文件的实现方法【小文件和大文件读取】
2016/09/19 Python
python列表使用实现名字管理系统
2019/01/30 Python
PyQt5 QTable插入图片并动态更新的实例
2019/06/18 Python
python tkinter GUI绘制,以及点击更新显示图片代码
2020/03/14 Python
Python中Qslider控件实操详解
2021/02/20 Python
如何用H5实现一个触屏版的轮播器的实例
2017/01/09 HTML / CSS
日本7net购物网:书籍、漫画、杂志、DVD、游戏邮购
2017/02/17 全球购物
Meli Melo官网:名媛们钟爱的英国奢侈手包品牌
2017/04/17 全球购物
京东港澳售:京东直邮港澳台
2018/01/31 全球购物
农药学硕士毕业生自荐信
2013/09/25 职场文书
社区工作者先进事迹
2014/01/18 职场文书
医院学雷锋活动策划方案
2014/02/15 职场文书
党课知识竞赛主持词
2014/04/01 职场文书
新郎婚礼答谢词
2015/01/04 职场文书
MySQL Shell import_table数据导入的实现
2021/08/07 MySQL