重构——重新组织函数

函数重构几乎都是源自于Long Methods。这导致了函数包含的信息过多,信息带来的逻辑错综复杂。

1 Extract Method(提炼函数)

<b>Summary:</b>将一段代码放进一个独立函数中,并让函数名称解释该函数的用途。
<b>Motivation:</b>将过长的函数分割成独立的函数,改善代码清晰度。
<b>Routine:</b>

  • 创造一个新函数,并根据意图命名;
  • 将提炼出的代码从源函数复制到新建的目标函数中;
  • 仔细检查提炼其中是否有源函数作用域的变量。
  • 检查是否有“仅用于被提炼代码段”的临时变量,有则在被提炼函数中将之声明位临时变量。
  • 检查被提炼代码段,看看是否任何局部变量的值被他改变。如果有临时变量的值被改变了,看看是否可将被提炼代码段提炼位一个查询,并将结果赋值给相关变量。如果被修改的变量不止一个,你就不能仅仅将这段代码原封不动地连出来。可能需要用到Split Temporary Variable,然后再尝试提炼。也可以使用Replace Temp with Query。
  • 被提炼代码段中需要读取的局部变量,当做参数传给目标函数。
  • 替代

2 Inline Method

<b>Summary</b>:再函数调用点插入函数本体,然后移除该函数。
<b>Motivation</b>:某些函数其内部结构和函数名同样清晰易读,也肯能是重构之后使其内容和名称变得同样清晰;手底下一些错误拆分的函数内联到一个大型函数中,再重新从中提炼小函数;中间层级过于多,导致了函数只是一个其余函数的代理。这三类是需要使用内联手法进行refacting。
<b>Routine</b>:

  • 检查函数,确定函数不具有多态性。
  • 找出函数的所有调用点。
  • 替换所有调用点的函数为其本体。
  • 编译,测试。
  • 删除函数定义。

3 Inline Temp 和 Replace Temp With Query

3.1 InlineTemp

<b>Summary:</b>将所有对该变量的引用动作替换位对它赋值的那个表达式自身。
<b>Motivation:</b>一般是作为Replace Temp with Query的一部分使用的,所以真正的动机是后者。唯一单独使用Line Temp的情况,某个临时变量被赋予某个函数调用的返回值,并阻碍了其他的重构手法。
<b>Routine:</b>

  • 检查给临时变量赋值的语句,确保等号右侧无副作用。
  • 如果这个临时变量未被声明位final,那就将它声明位final编译,从而验证赋值状况。
  • 找到所有调用点并替换。
  • 编译测试。
  • 删除赋值语句和临时变量。编译测试。

3.2 Replace Temp With Query(以查询代替临时变量)

Summary:将这个表达式提炼到一个独立函数中。将这个临时变量的所有引用点替换位对新函数的调用。此后,新函数就可以被其他函数调用。

double basePrice =_quantity * _itemPrice;
if(basePrice>1000)
  return basePrice * 0.95;
else 
  return basePrice * 0.98;
……
double basePrice(){
  return _quantity * _itemPrice;
}

<b>Motivation:</b>临时变量是暂时的,只能在所属函数内使用。由于临时变量只在所属函数内可见,所以它们会驱使你写更长的函数。如果把临时变量替换位一个查询,那么同一个类中的所有函数都将可以获得这份信息。这将带来极大的帮助,写除清晰的代码。
<b>Routine:</b>

  • 找出只被赋值一次的临时变量(如果赋值超过一次,可以考虑Split Temporary Variable)。
  • 将临时变量声明位final。
  • 编译。
  • 提炼等号右侧部分到一个独立函数中。
  • 编译,测试。
  • 在该临时变量身上使用Inline Temp。

4 Introduce Explaining Variable(引入解释性变量)

<b>Summary:</b>将复杂表达式(或者其中一部分)的结果放进一个临时变量,以此变量名称来解释表达式用途。
<b>Motivation:</b>在条件逻辑中,判定条件往往相当复杂,引入解释性变量来对应其意义来明晰代码逻辑;另外,在较长的算法中,可以运用临时变量来解释每一步运算的意义。
<b>Routine:</b>

  • 声明一个final临时变量,将待分解之复杂表达式中的一部分动作的运算结果赋值给它。
  • 将运算结果的相应部分替换位上述变量。
  • 编译,测试。
  • 重复上述过程。

5 Split Temporary Variable(分解临时变量)

<b>Summary:</b>针对每次赋值,创造一个独立,对应的临时变量。
<b>Motivation:</b>临时变量有各种不同用途,其中某些用途会很自然地导致临时变量被多次赋值。循环变量和循环收集变量就是其中的典型例子。除了这两种情况,还有很多临时变量用于保存一段冗长代码的运算结果,以便稍后使用。这种临时变量应该只有一次赋值,赋值多次就代表这临时变量承担多个责任,就应该被分解替换。
<b>Routine:</b>

  • 在待分解变量的声明及其第一次被赋值处,修改其名称。(如果是结果收集变量和循环变量则不要分裂)
  • 将新的临时变量声明位final。
  • 以该临时变量的第二次赋值动作位界,修改此前对该临时变量的所有引用点,让它们引用新的临时变量。
  • 在第二次赋值处,重新声明原先那个临时变量。
  • 编译,测试。
  • 重复执行上述过程。

6 Remove Assignments to Parameters(移除对参数的赋值)

<b>Summary:</b>以一个临时变量取代该参数的位置。
<b>Motivation:</b>这会降低代码的清晰度,会让人搞不清楚是参数的值域被修改还是新的被指向的值域被修改。
<b>Routinue:</b>

  • 建立一个临时变量,把待处理的参数值赋予给它。
  • 以此位置为界,将其后所有对此参数的引用点,全部替换为此临时变量的引用。
  • 修改赋值语句,使其改为对新建值临时变量的赋值。
  • 编译,测试。

7 Replace Method with Method Object(以函数对象取代函数)

<b>Summary:</b>将函数放进一个单独对象中,如此一来局部变量就成了对象内的字段。然后可以在一个对象中将大型函数切分位多个小型函数。
<b>Motivation:</b>如果一个函数之中局部变量泛滥成灾,那么像分解这个函数是非常困难的,当Replace Temp with Query无法更笨上拆解一个函数时,应该用对象。
<b>Routinue:</b>

  • 建立一个新类,根据职责命名。
  • 在新类中建立一个final字段,泳衣保存原先大型函数所在对象,针对原函数的每个临时变量和参数,在新类中建立对应的字段保存。
  • 在新类的构造函数传入源对象和所有参数。
  • 在新类中建立函数,在函数中粘贴进源代码。
  • 编译。
  • 将旧函数的函数本体替换位创建一个新对象,并调用相应函。

8 Substitute Algorithm(替换算法)

<b>Summary:</b>把某个算法替换位更清晰的算法。
<b>Motivation:</b>替换更好或者更易修改的函数。
<b>Routinue:</b>

  • 准备好替换算法。
  • 执行新算法。
  • 以旧算法位标准修正新算法。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,732评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,496评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,264评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,807评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,806评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,675评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,029评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,683评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,704评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,666评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,773评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,413评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,016评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,204评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,083评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,503评论 2 343

推荐阅读更多精彩内容