在编程中,比较忌讳的一件事情就是长函数。因为长函数代表了你这段代码不能很好的复用以及内部可能出现很多别的地方的重复代码,而且这段长函数内部的处理逻辑你也不能很好的看清楚。因此,今天重构第一个手法就是处理长函数--Extract Method,抽取成一个独立的小函数。

我个人来说也很喜欢短小函数,因为他们代表了高强度的复用与灵活性。对于短小函数来说最最关键的就是短小函数的命名,其实你就是给了这些短小函数自我解释的机会,所以你如果给这些短小函数起一个接近其语义的名字,那当你读起长函数来说,就像是阅读一篇你设计好的故事。这个对于你之后的编程也是非常关键的。之前看到一篇文章说过,编程大牛与新手其中一个最重要的区别就是他们对于函数和类以及变量的命名非常谨慎。而我们往往一开始从学校走出来都是清一色的被老师教的i,j,k,尽快改掉这个习惯吧,现在的屏幕这么大,你也不需要去考虑纸张的问题,让变量,函数,类能够解释自身,省去你重新去理解的机会,这样岂不是更好?

一般来说,当你看到长函数,或者一堆函数实现挤在一起,意味着你需要对他们进行分离,又或者你需要实际下手为一堆函数写一个能够让人理解的注释的时候,表示你差不多也需要进行Extract Method了。其实很多时候,只有当你整理了这些函数之后,你才能看到高层应该能够看到的东西。比如这些代码段出现的位置,依赖的具体类更合适的是哪个,函数之间的逻辑关系有没有重复等等。因此,Extract Method能够帮助我更好的理解代码,能够站在更高的角度上去看待一些事情。『重构』一书中作者也提到,当他开始查看别人的代码或者接手别人的工作的时候,对于一些需要Extract Method的地方他会毫不犹豫去修改,重新命名。因为这个重构过程实质就是一个帮助你更好理解的过程。

Extract Method其实很简单,就是把在原来函数的内部的那些语句抽离出来,然后放到一个独立的目标小函数中去,然后在原来函数中的地方修改成对目标函数的调用就可以。但其中需要注意的地方就是局部变量这个东西。下面我们直接看第一个小例子

void printOwing()
{
// print banner
cout << "*********" << endl;
cout << "**Baner**" << endl;
cout << "*********" << endl;
}

这个例子是最简单的没有局部变量的例子,图中可以看到作者为了让你明白他接下来的3句是打印banner,特意加了注释。其实我们自己也可以看到这三句逻辑性其实就是应该放在一块,所以我们第一步就是创建目标函数printBanner,将这个代码片段复制进去。

void printBanner()
{
cout << "*********" << endl;
cout << "**Baner**" << endl;
cout << "*********" << endl;
}

接下来我们就是找到原来函数的引用点,将这个代码片段替换成对目标函数的调用。

void printOwing()
{
printBanner();
}

这样即完成了对这个函数的重构。下面来看第二个例子,注意,这个时候开始带局部变量了。(包括源函数的参数以及在源函数下声明的临时变量)

void printOwing()
{
QString bannerVersion = QString("1.0"); // print banner
cout << "*********" << endl;
cout << "**Baner**" << bannerVersion << endl;
cout << "*********" << endl;
}

注意这里的区别,此时已经用到了临时变量bannerVersion.并且这个变量是在源函数下声明的,仔细观察可以看到我的提炼代码段并不会去修改他们而是简单的去读取他们,因此我们可以把这种当作参数传给目标函数

void printOwing()
{
QString bannerVersion = QString("1.0"); printBanner(bannerVersion);
} void printBanner(const QString &value)
{
cout << "*********" << endl;
cout << "**Baner**" << value << endl;
cout << "*********" << endl;
}

这样就完成了对于这种情况的重构。停下来看看我们做了什么,有些同学可能觉得这不就是把原来的长函数变成短函数了吗?但你仔细观察你会看到,是的,复用来了,对于我提炼的printBanner这个函数,我只需要一个QString,我就可以完成打印banner的功能,并且灵活性也来了,我可以自由改变版本号version。

接下来我们看第三个例子

void printOwing()
{
Enumeration e = _orders.elements();
double outstanding = 0.0; printBanner(); // calcalate outstanding
while (e.hasMoreElements())
{
Order each = e.nextElement();
outstanding += each.getAmount();
}
}

在这个例子中,我们需要重构分离出计算outstanding的计算过程,但我们发现了临时变量outstanding需要在目标函数里进行赋值更改,所以我们必须通过目标函数来把它返回,又因为源函数的Enumeration e这个变量只在被提炼代码中会被用到,所以我们可以直接转移他进目标函数,并且发现outstanding这个变量其实就是一个初始化,因此我们最后提炼可以得到这样的结果

void printOwing()
{
printBanner();
double outStanding = getOutstanding();
} double getOutstanding()
{
Enumeration e = _orders.elements();
double outstanding = 0.0; // calcalate outstanding
while (e.hasMoreElements())
{
Order each = e.nextElement();
outstanding += each.getAmount();
} return outstanding;
}

另外还有一种情况就是这个变量既需要目标函数作为返回,又需要目标函数对其做处理,则需要将这个变量传给目标函数并将结果返回出来

void printOwing(int val)
{
Enumeration e = _orders.elements();
double outstanding = val * ; // calcalate outstanding
while (e.hasMoreElements())
{
Order each = e.nextElement();
outstanding += each.getAmount();
}
}

对于这种情况我们就要做到既要变量传入,也要将结果传出

void printOwing(int val)
{
double outstanding = val * ;
printBanner();
outStanding = getOutstanding(outStanding);
} double getOutstanding(int intialValue)
{
Enumerition e = _orders.elements();
double outstanding = intialValue; // calcalate outstanding
while (e.hasMoreElements())
{
Order each = e.nextElement();
outstanding += each.getAmount();
} return outstanding;
}

这样即完成了对于拥有临时变量的函数进行Extract Method,希望你会喜欢:)

『重构--改善既有代码的设计』读书笔记----Extract Method的更多相关文章

  1. 『重构--改善既有代码的设计』读书笔记----Replace Method with Method Object

    有时候,当你遇到一个大型函数,里面的临时变量和参数多的让你觉得根本无法进行Extract Method.重构中也大力的推荐短小函数的好处,它所带来的解释性,复用性让你收益无穷.但如果你遇到上种情况,你 ...

  2. 『重构--改善既有代码的设计』读书笔记----Move Method

    明确函数所在类的位置是很重要的.这样可以避免你的类与别的类有太多耦合.也会让你的类的内聚性变得更加牢固,让你的整个系统变得更加整洁.简单来说,如果在你的程序中,某个类的函数在使用的过程中,更多的是在和 ...

  3. 『重构--改善既有代码的设计』读书笔记----Extract Class

    在面向对象中,对于类这个概念我们应该有一个清晰的责任认识,就是每个类应该只有一个变化点,每个类的变化应该只受到单一的因素,即每个类应该只有一个明确的责任.当然了,说时容易做时难,很多人可能都会和我一样 ...

  4. 『重构--改善既有代码的设计』读书笔记----Inline Method

    加入间接层确实是可以带来便利,但过多的间接层有时候会让我自己都觉得有点恐怖,有些时候,语句本身已经够清晰的同时就没必要再嵌一个函数来调用了,这样只会适得其反.比如 void test() { if ( ...

  5. 『重构--改善既有代码的设计』读书笔记----Introduce Foreign Method

    当你无法获得一个类的源代码或者没有权限去修改这个类的时候,你对于这种为你服务的类,你可能会出现需要别的需求的时候,比如一个Date类,你需要能够让他本身直接返回出他的后一天的对象,但他没有,这个时候你 ...

  6. 『重构--改善既有代码的设计』读书笔记----Replace Temp with Query

    Replace Temp with Query,顾名思义,表示你用查询来替换临时变量本身,临时变量对于函数来说是只有当前函数可见的,如果你在同类的别的地方要用到这个变量你就必须重新写表达式来获取这个变 ...

  7. 『重构--改善既有代码的设计』读书笔记----Substitute Algorithm

    重构可以把复杂的东西分解成一个个简单的小块.但有时候,你必须壮士断腕删掉整个算法,用简单的算法来取代,如果你发现做一件事情可以有更清晰的方式,那你完全有理由用更清晰的方式来解决问题.如果你开始使用程序 ...

  8. 『重构--改善既有代码的设计』读书笔记----Introduce Explaning Variable

    有时候你会遇到一系列复杂的表达式连续运算的时候,这个时候你可能根本招架不住如此长或者是如此复杂的长函数.这个时候你可以通过引用临时变量来储存他们的结果,将这些长函数的结果分成一个个临时变量来让函数清晰 ...

  9. 『重构--改善既有代码的设计』读书笔记----Change Value to Reference

    有时候你会认为某个对象应该是去全局唯一的,这就是引用(Reference)的概念.它代表当你在某个地点对他进行修改之后,那么所有共享他的对象都应该在再次访问他的时候得到相应的修改.而不会像值对象(Va ...

随机推荐

  1. poj2594

    特殊的最小路径覆盖回顾一下经典的最小路径覆盖问题是每个点都恰好被一条路径覆盖我们把有向无环图的点拆成i,i',对于原图中边i--->j,连边i-->j'做最大匹配,答案是原图点数-最大匹配 ...

  2. 数据结构(括号序列,线段树||点分治,堆):ZJOI 2007 捉迷藏

    [题目描述] Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiajia.Wind和孩子们决定在家里玩捉迷藏游戏.他们的家很大且构造很奇特,由N个屋子和N-1条双向走廊组成,这N- ...

  3. 数学(组合,容斥):COGS 1220. 盒子与球

    1220. 盒子与球 ★   输入文件:boxball.in   输出文件:boxball.out   简单对比 时间限制:1 s   内存限制:128 MB [问题描述] 现有r个互不相同的盒子和n ...

  4. 【动态规划】Vijos P1037 搭建双塔

    题目链接: https://vijos.org/p/1037 题目大意: 给n块砖的长度(n<=100),问从中任选m块砖能否建成2个相同高度的塔. 能的话求最高高度,不能输出 Impossib ...

  5. iOS: 关于Certificate、Provisioning Profile、App ID的介绍及其之间的关系

    刚接触iOS开发的人难免会对苹果的各种证书.配置文件等不甚了解,可能你按照网上的教程一步一步的成功申请了真机调试,但是还是对其中的缘由一知半解.这篇文章就对Certificate.Provisioni ...

  6. Fill-倒水问题(Uva-10603-隐式图路径寻找问题)

    原题:https://uva.onlinejudge.org/external/106/10603.pdf 有三个没有刻度的杯子,它们的容量分别是a, b, c, 最初只有c中的杯子装满水,其他的被子 ...

  7. sql server2008 搭建链接服务器成功后查询时报Cannot obtain the schema rowset "DBSCHEMA_TABLES_INFO" for OLE DB provider "SQLNCLI10" for linked server "XXXXX". 的解决方法

    这是由于链接的数据库服务器的版本与本地数据库服务器不一致,有人说要升到sp3,sp4,然后在执行什么语句之类的 我觉得太繁琐了,通过网上查询之后看到可以这么做: USE master GRANT EX ...

  8. Mysql学生管理系统:表的建立,外键一对多,多对多关系,中间关联表的建立

    学生管理系统 管理员注册/登录/注销 注册班级(班级详细信息) 注册学生信息 查看班级信息/查看老师资料 教师注册/注销  查看教师资料  查看学生资料  根据名称/班级/ 查看学生详细信息--支持模 ...

  9. setTimeout的作用以及setTimeout延时0毫秒的作用

    以下代码输出的顺序是? console.log(1); setTimeout(function(){ console.log(2); }, 0); setTimeout(function(){ con ...

  10. PyCharm4注册码

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 name : newasp == ...