《重构:改善既有代码的设计》读书笔记1——重新组织函数
https://www.jianshu.com/p/d91987818ee6
(1):Extract Method 提炼函数:
当看到一个过长函数或需要注释才能让人理解用途的代码,需要将这段代码放进一个独立函数中。
- 如果每个函数粒度都很小,那么函数被复用的机会就更大
- 每个小函数起一个好名字,读这些函数就像读注释。
- 覆写起来更容易。
注意点:如果你想不到一个有意义的名字,先别动。
例子:
1 void printOwing(double amount){ 2 printBanner();
//print details 3 System.out.println("name"+_name); 4 System.out.println("amount"+_amount); 5 }
==>
void printOwing(double amount){ printBanner(); printDetails(amount); } void printDetails(double amount){ System.out.println("name"+_name); System.out.println("amount"+_amount); }
Extract method通常会遇到三种情况:无局部变量、有局部变量(只读,修改)。
- 无局部变量情况下,只需抽取即可。
- 有局部变量,但被提炼的代码段只是读取这些变量的值并不修改它们,可以简单的将它们作为参数传给目标函数即可。
- 如果被提炼的代码段对局部变量赋值。此时情况变得更复杂了。
-
- 这个变量只在被提炼的代码段中使用,可以将这个变量移到被提炼的代码段中。
- 在被提炼的代码段之外也使用了。只需要让目标函数增加返回值即可。
(2):Inlined Method(内联函数)
有时候会遇到函数,其内部代码和函数名称同样清晰易读。也可能你重构了该函数,使得其内容和名称同样清晰。果真如此,你就应该去掉这个函数,直接使用其中代码,间接性可能带来帮助,但非必要的间接性让人总是不舒服。
其次,你手上有一群组织不甚合理的函数,可以将它们都内联到一个大型函数中,在从中提炼出组织合理的小型函数,
例:
1 int getRating(){ 2 return(moreThanFiveLateDeliveries()) ? 2:1; 3 } 4 boolean moreThanFiveLateDelivers(){ 5 return _numberOfLateDeliveries>5; 6 } 7 8 --》 9 10 int getRating(){ 11 return (_numberOfLateDeliveries>5)?2:1; 12 }
(3) 内联临时变量 Lnline Temp 临时变量只被表达式赋值一次,将所有对该变量的引用动作,替换为对它赋值的那个表达式自身。
(4)Replace Temp with Query(以查询取代临时变量)
你的程序以一个临时变量保存某一表达式的运算结果。将这个表达式提炼到一个独立的函数中。将这个临时变量的所有引用点替换为对新函数的调用
例,略。
好处:临时变量只能在所属函数内使用。由于临时变量只在所属函数内可见,所以它们会驱使你写出更长的函数。如果把临时变量替换成一个查询,那么同一类中所有的函数都将可以获得这份信息。
(5)Introduce Explaining Variable(引入解释性变量)
将复杂的表达式(或其中一部分)的结果放进一个临时变量,以此变量名称来解释表达式的用途。------更多的extract method()处理。当extract method需要花费大量工作量时 才使用该方法。
例:
1 if((platform.toUpperCase().indexof("MAC")>-1)&&(browser.toUpperCase().indexof("IE)>-1)&& 2 wasInitialized()&&resize>0){ 3 //do something 4 } 5 --》 6 final boolean isMac=platform.toUpperCase().indexof("MAC")>-1; 7 final boolean isIE=browser.toUpperCase().indexof("IE)>-1; 8 final boolean wasResized=resize>0; 9 if(isMac&&isIE&&wasInitialized()&&wasResized){ 10 // 11 }
(6)Split Temporary Variable(分解临时变量)
针对每次赋值,创造一个独立、对应的临时变量。如果临时变量被赋值超过一次,就意味着在函数中承担多个责任,它就应该被替换分解为多个临时变量,每个变量只承担一个责任。
double temp=2*(_height+_width) System.out.println(temp); temp=_height*_width; System.out.println(temp); --》 final double perimeter = 2*(_height+_width); final double area=_height*_width;
(7)Remove Assignments to Parameters(移除对参数的赋值)
代码对一个参数进行赋值,以一个临时变量取代该参数的位置。在java代码中,不要对参数赋值。!!!
可以在参数列表中添加final !。 但即使参数为final 仍可修改它所指向的对象。
(8)replace method with method object 以函数对象取代函数。
有一个大型函数,其局部变量的使用是你无法采用extract method. 将这个函数放进一个单对对象中,如此一来局部变量就变成对象内的字段,后你可以在同一个对象中将这个大型函数分解成为多个小函数。
(9)替换算法。
将函数本体替换成另一种算法。请尽可能的分解原先的函数,替换一个巨大而复杂的算法是非常困难的。