文档章节

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

fzxu_05
 fzxu_05
发布于 2015/12/06 17:08
字数 2270
阅读 63
收藏 6

 专业术语

 

我们毕竟是用英文字母编码,所以用一些英语单词,更能显示出我们的专业性。以下的英文单词,你如果掌握了,与其他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。

 

动机:随着对问题有了更多的了解,你发现一件事可以有更清晰的方式,就应该以较清晰的方式取代复杂方式。

本文转载自:

fzxu_05
粉丝 43
博文 165
码字总数 84201
作品 0
朝阳
程序员
私信 提问
[读书]读《重构-改善既有代码的设计》

读《重构-改善既有代码的设计》 断断续续,加上过年,花了快2个月吧,把《重构-改善既有代码的设计》读完了,这里总结下。 发现此书背景 读的感觉 知识感触 发现此书背景 这本书是从同事的桌...

zemel
2016/03/07
41
0
读书笔记《重构 改善既有代码的设计》

重构 (refactoring) 在不改变代码的外在的行为的前提下 对代码进行修改最大限度的减少错误的几率 本质上, 就是代码写好之后 修改它的设计。 1,书中开始用一个例子简单阐释为什么要重构,以...

MichaelDuan
09/29
0
0
重构-改善既有代码设计

重构是在不改变软件可观察行为的前提下,对代码作出修改,以改进程序的内部结构。本质上说就是在代码写好后改进它的设计 重构往往意味着不了解软件行为下重构程序 2.在设计前期使用模式常常导...

zhchl2010
2015/12/24
128
0
重构你的javascript代码

重构,对于每个开发者都至关重要,特别是对于那些需要进阶的高级程序员。根据二八理论,20%的重构方法,能解决80%的坏代码。笔者最近查阅较多js编码指南以及重新阅读了《代码整洁之道》、《重...

lq782655835
01/22
0
0
31 天重构学习笔记2. 移动方法

摘要:由于最近在做重构的项目,所以对重构又重新进行了一遍学习和整理,对31天重构最早接触是在2009年10月份,由于当时没有订阅Sean Chambers的blog,所以是在国外的社区上闲逛的时候链接过...

技术小甜
2017/11/15
0
0

没有更多内容

加载失败,请刷新页面

加载更多

3_数组

3_数组

行者终成事
20分钟前
3
0
经典系统设计面试题解析:如何设计TinyURL(二)

原文链接:https://www.educative.io/courses/grokking-the-system-design-interview/m2ygV4E81AR 编者注:本文以一道经典的系统设计面试题:《如何设计TinyURL》的参考答案和解析为例,帮助...

APEMESH
今天
7
0
使用logstash同步MySQL数据到ES

概述   在生成业务常有将MySQL数据同步到ES的需求,如果需要很高的定制化,往往需要开发同步程序用于处理数据。但没有特殊业务需求,官方提供的logstash就很有优势了。   在使用logstas...

zxiaofan666
今天
10
0
X-MSG-IM-分布式信令跟踪能力

经过一周多的鏖战, X-MSG-IM的分布式信令跟踪能力已基本具备, 特点是: 实时. 只有要RX/TX就会实时产生信令跟踪事件, 先入kafka, 再入influxdb待查. 同时提供实时sub/pub接口. 完备. 可以完整...

dev5
今天
7
0
OpenJDK之CyclicBarrier

OpenJDK8,本人看的是openJDK。以前就看过,只是经常忘记,所以记录下 图1 CyclicBarrier是Doug Lea在JDK1.5中引入的,作用就不详细描述了,主要有如下俩个方法使用: await()方法,如果当前线...

克虏伯
今天
8
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部