从文章"避免复制与粘贴"到文章"Extract Method"的反思(2)
好了.在上一篇里面讲了讲怎么把临时变量应该从函数里面剔除去.这个过程叫做从临时变量变成查询
那么接下来我们聊聊把代码提炼成函数,有叫做用函数对象取代函数
那么,问题来了:在函数中什么样的代码是需要被提炼出来单独成为函数的? 一般而言 代码里面的注释会指出 代码用途 和 实现手法直接的语义距离. 这里就暗示着如果代码前方有一行注释的话就以为这这里是需要提炼成函数的,并且可以在代码的基础上给这行代码命名(所以啊,这里的函数名很重要,因为他还承担了注释的作用,要让人看了这个函数名就能知道这个函数在干神马). 就算是一行代码,如何需要用注释来说明的话,也是有必要提炼成函数的.
----->
这里还有一些现场的规则来指导我们怎么做:
做法:
1、创造一个新函数,根据这个函数的意图对它命名(以它“做什么“命名,而不是以它“怎样做”命名)。
即使你想要提炼的代码非常简单,例如只是一条消息或一个函数调用,只要新函数的名称能够以更好方式昭示代码意图,你也应该提炼它。但如果你想不出一个更有意义的名称,就别动。
2、将提炼出的代码从源函数复制到新建的明白函数中。
3、仔细检查提炼出的代码,看看其中是否引用了“作用域限于源函数”的变量(包括局部变量和源函数参数)。
4、检查是否有“仅用于被提炼代码段”的临时变量。如果有,在目标函数中将它们声明为临时变量。
5、检查被提炼代码段,看看是否有任何局部变量的值被它改变。如果一个临时变量值被修改了,看看是否可以将被提炼代码处理为一个查询,并将结果赋值给修改变量。如果很难这样做,或如果被修改的变量不止一个,你就不能仅仅将这段代码原封不动提炼出来。你可能需要先使用Split Temporary Variable (分解临时变量),然后再尝试提炼。也可以使用 Replace Temp with Query (以查询取代临时变量)将临时变量消灭掉。
6、将被提炼代码段中需要读取的局部变量,当做参数传给目标函数。
7、处理完所有局部变量后,进行编译。
8、在源函数中,将被提炼代码段替换给对目标函数的调用。
如果你将如何临时变量移到目标函数中,请检查它们原本的声明式是否在被提炼代码段的外围。如果是,现在可以删除这些声明式了。
9、编译,测试。
函数中的条件表达式和循环也是提炼的信号. 循环没什么好言明的,应该讲循环和循环内部的代码提炼成一个函数. 接下来讲讲 条件表达式的提炼 官方叫做分解条件表达式
所谓的条件表达式就是下面的形式
if
.......
then
.......
else
......
分解条件表达式的动机:复杂的条件逻辑是程序复杂度上升点之一.因为你必须编写代码来判断不同的条件,而不同的条件下有做不同的事情.因为就会得到一个相当大的函数了.相当大的函数本身就意味着可读性的降低而条件逻辑则会使代码更难阅读。在带有复杂条件逻辑的函数中,代码(包括检查条件分支的代码和真正实现功能的代码)会告诉你发生的事,但常常让你弄不清为什么会发生这样的事
而我们分解条件表达式就是为了能够突出条件的逻辑结构.
看下面的例子吧:
------>
实际工作中,要一步一步的进行每一次的条件表达式的提炼,并在每次提炼之后编译并测试。这里需要注意的是,一般条件下我们程序员可能都不会去提炼条件,可能是因为这些条件非常短[指的是if(xxx)--->这里的xxx].但是尽管可能很短,很可能在代码意图和代码自身之间存在很大的差距.就像上面的例子 notSummer(data) 就要比 date.before(SUMMER_START) || date.after(SUMMER_END)这样的逻辑条件跟好的表达出代码的用途来,从而看起来就像是注释一样的清晰明了.
看完例子我们再回头聊一聊,条件表达式应该怎么具体操作:
1、将if段落提炼出来,构成一个独立函数。
2、将then和else段落提炼出来,各自构成一个独立函数。
好吧其实意思就是把if{代码1}then{代码2}else{代码3}中的代码1,代码2,代码3都最好搞成独立函数.而且看看if的条件是不是表达的很清晰,否则也搞成函数..
在牛人的关于提炼条件表达式的简洁中有下面的一句话
如果发现嵌套的条件逻辑,先观察是否可以使用Replace Nested Conditional with Guard Clauses (以卫语句取代嵌套条件表达式)。如果不行,才开始分解其中的每个条件。
针对这句话,在展开一个交流点
好吧,上面这句话中的什么叫做 嵌套的条件逻辑, 我承认我没弄明白. 不过没影响.这里要聊聊的是 以卫语句取代嵌套条件表达式 .还是看例子吧.有的时候文字看着晕乎,还不如直接看例子.再返回头看文字,就理解了..
一般而言条件表达式有两种形式
第一种:所有条件都是正常流程
例如:对人的身高的判断
if(中国人) ....
else if (美国人) ....
else if(欧洲人) .....
第二种:所有条件中只有一种正常形式,其他都是不常见或者异常的情况
例如: 对人的特征的判断
if(是人) ....
else if( 是动物) ... //异常
else if(是植物) .... //异常
对于第一种情况而言我们就要用正常的if then else
对于第二种情况而言就应该单独检查该条件,这种单独检查就被称为“卫语句”(guard clauses).意思是一个一个的用if拆开,而不要用if then else来搞了.. 看下面例子吧
例如:
解析来就进入主题,讲一讲 在代码开发中药避免复制和粘贴..看下一个篇幅吧
从文章"避免复制与粘贴"到文章"Extract Method"的反思(2)的更多相关文章
- 从文章"避免复制与粘贴"到文章"Extract Method"的反思(3)
在牛人的博客中提到了..如果你的代码可以copy-past的时候,那么久证明你的代码出现了重复.而这种重复仅仅是虚假的代码行的增加而不是像其他的代码复用那样降级成本. copy-pase代码意味着你违 ...
- 从文章"避免复制与粘贴"到文章"Extract Method"的反思(1)
看了一个比我牛的人的博客园的博文"避免复制和粘贴".里面提到了重构手法Extract Method. 所以又搜了一下Extract Method. 这里先自我理解Extract ...
- 如何在eclips下将一段代码抽取为方法Extract Method
最近读了读关于重构的文章,做了个小总结(在编程思想目录下<从文章"避免复制与粘贴"到文章"Extract Method"的反思 系列>). 然后因为 ...
- Laravel大型项目系列教程(四)显示文章列表和用户修改文章
小编心语:不知不觉已经第四部分了,非常感谢很多人给小编提的意见,改了很多bug,希望以后能继续帮小编找找茬~小编也不希望误导大家~这一节,主要讲的 是如何显示文章列表和让用户修改文章,小编预告一下(一 ...
- 用python+selenium登录cnblog后新增文章后再次删除该文章
目的:登录cnblog后新增文章后再次删除该文章并验证 代码如下: #coding: utf-8 from selenium import webdriver from time import sle ...
- dedecms文章页调用地址(当前文章URL)如何操作?
我们在建站时经常会在文末加一个本文地址,那么dedecms文章页如何调用当前文章URL呢?这样做的好处是增加文章的唯一标识,更进一步的做法是在head中加个cannacial标签,告诉搜索引擎url的 ...
- VS Extract Method
前言 看重构6.4Replace Temp with Query(以查询取代临时变量)中提到Replace Temp with Query往往是你运用Extract Method之前必不可少的一个步骤 ...
- 『重构--改善既有代码的设计』读书笔记----Extract Method
在编程中,比较忌讳的一件事情就是长函数.因为长函数代表了你这段代码不能很好的复用以及内部可能出现很多别的地方的重复代码,而且这段长函数内部的处理逻辑你也不能很好的看清楚.因此,今天重构第一个手法就是处 ...
- Refactoring #001 Extract Method
Example public void startup() { ServerSocket serverSocket = null; try { serverSocket = new ServerSoc ...
随机推荐
- Yii 设置 flash消息 创建一个渐隐形式的消息框
/*适用情况:比如提交一个表单,提交完成之后在页面展示一条提示消息. 控制器里面这样写: 单条消息: */ \Yii::$app->getSession()->setFlash('erro ...
- IOS开发之UINavigationBar
简介 UINavigationBar是用于实现管理层级关系内容的组件,直接继承自UIView.通常用在UINavgationController类中,用于管理和显示UINavgationControl ...
- swift小结02-基础篇
闭包 类似于 OC 中的 Block,是一段预先定义好的代码,在需要时执行 闭包表达式格式: { (形参名称1: 形参类型1, 形参名称2: 形参类型2, ...) -> 返回值 ...
- android关机充电
1.关机充电其实是进入adb shell很快的方式! 2.手机关机时候插入USB,手机将进入关机充电模式,那么这个模式究竟是怎么进行的,这里分析如下! (1)uboot:这里代码大概浏览了一下:u-b ...
- SQL2008和SQL2000可以跨服务器连接查询的测试实例
测试目的: SQL2008 和 SQL2000 是否可以跨服务器连接查询 -- 测试环境: --A 虚拟机 XP ( IP : .0.0.213 )安装 SQL2000 个人版,并安装 SP4 补丁. ...
- 应用Druid监控SQL语句的执行情况--转载
Druid是什么? Druid首先是一个数据库连接池.Druid是目前最好的数据库连接池,在功能.性能.扩展性方面,都超过其他数据库连接池,包括DBCP.C3P0.BoneCP.Proxool.JBo ...
- javascript如何列出全局对象的非原生属性。
Why 研究一个网站前端技术的时候,了解它的全局的对象是一个好的入口, 一般来说,常见的库就会用外观模式,最后暴露一个对象给用户调用, 比如jQuery,requirejs,angular,react ...
- C# QRCode、DataMatrix和其他条形码的生成和解码软件
今天制造了一个C#的软件,具体是用于生成二维码和条形码的,包括常用的QRCode.DataMatrix.Code128.EAN-8等等. 使用的第三方类库是Zxing.net和DataMatrix.n ...
- 再次回首 TCP Socket服务器编程
转载:http://www.cnblogs.com/zc22/archive/2010/06/27/1766007.html ------------------ 前言 --------------- ...
- java Junit 测试中异常处理
错误提示: junit.framework.AssertionFailedError: No tests found in错误解决办法 用junit Test运行后,出现如下的错误:junit.fra ...