代码重构之重新组织函数
2017-11-25 15:41
417 查看
一、提炼函数(Extract Method)
动机:当函数过长或者需要注释才能理解用途的代码
做法:
创造一个新函数,根据这个函数的意图来命名
将提炼出来的代码从源函数复制到新的目标函数中
仔细检查提炼出来的代码,看看是否引用了" 作用域限于源函数"的变量
检查是否有"仅用于被提炼函数的代码段"的临时变量,如果有在目标函数中声明临时变量
检查被提炼代码段,看看是否有局部变量的值被它改变,如果临时变量的之被改变了,看看是否可以将被提炼代码处理为一个查询,并将结果赋值给相关变量,如果很难这么做,你需要先使用Split Temporary Variable,然后尝试提炼。(也可以使用Replace Temp with Query)
将被提炼代码中需要读取的局部变量,当作参数传给目标
范例:
源代码
重构
二、内联函数(Inline Method)
动机:内部代码和函数名一样清晰易懂或者有一群不甚合理的函数(Replace Method with Method Object)
做法:
检查函数,确定它不具多态性
找出这个函数所有被调用点
将这个函数所有被调用点替换为函数本体
范例:
源代码
重构
三、内联临时变量(Inline Temp)
动机:临时变量妨碍其他的重构手法时(如Replace Temp with Query)
做法:
检查给临时变量赋值的语句,确保等号右边的表达式没有副作用
如果这个临时变量未被声明为final,那么将他声明为final(编译检查,该变量是否只赋值一次)
找到所有该临时变量的引用点,修改为表达式,并删除这个临时变量
范例
源代码
重构
四、以查询取代临时变量(Replace Temp with Query)
动机:其他重构手法难以进行时(如Extract Method)
做法:
找出只被赋值一次的临时变量
声明为final(编译检测一次性)
将这个临时变量的等号右侧提炼到独立函数中
范例:
源代码
重构
五、引入解释性变量(Introduce Explaining Variable)
动机:表达式复杂而难以理解时,临时变量可以帮助容易阅读
做法:
声明一个final临时变量,将待分解之复杂表达式中的一部分动作的运算结果赋值给他
将表达式中的"运算结果",替换为上述临时变量
范例:
源代码
重构
六、分解临时变量(Split Temporary Variable)
动机:临时变量被赋值超过一次(除循环和结果收集外)
做法:
在待分解临时变量的声明及其第一次被赋值处,修改其名称
将新的临时变量声明为final
以该临时变量的第二次赋值动作为临界点,修改此前对该临时变量的所有引用点,让他们引用新的临时变量
在第二次赋值处,重新声明原先那个临时变量
重复上述过程,直到临时变量被赋值一次为止
范例:
源代码
重构
七、以函数对象取代函数(Replace Method With Method Object)
动机:函数中局部变量泛滥,而无法进行Extract Method时
做法:
建立一个新类,根据待处理函数用途,来命名
在新建类中建立final字段,用以保存原先大型函数所在的对象,每个临时变量和参数建立对应的字段保存。
在新类中建立构造函数,接收源对象以及原函数的所有参数作为参数
在新类中建立一个Compute()
将原函数的代码复制到compute()中,如果需要调用源对象的任何函数,通过源对象字段调用
将旧函数的函数体替换为:创建上述新类对象,并调用compute()
范例:
源代码
重构
八、移除对参数的赋值(Remove Assignment To Parameters)
动机:被传入对象指向一个新的对象
做法:
建立临时变量,把带待处理的对象赋值给他
以"对参数的赋值"为界,将其后所有对此参数的引用,全部替换为"对此临时变量的引用"
修改赋值语句,使其改为对新建之临时变量赋值
范例:
源代码
重构
动机:当函数过长或者需要注释才能理解用途的代码
做法:
创造一个新函数,根据这个函数的意图来命名
将提炼出来的代码从源函数复制到新的目标函数中
仔细检查提炼出来的代码,看看是否引用了" 作用域限于源函数"的变量
检查是否有"仅用于被提炼函数的代码段"的临时变量,如果有在目标函数中声明临时变量
检查被提炼代码段,看看是否有局部变量的值被它改变,如果临时变量的之被改变了,看看是否可以将被提炼代码处理为一个查询,并将结果赋值给相关变量,如果很难这么做,你需要先使用Split Temporary Variable,然后尝试提炼。(也可以使用Replace Temp with Query)
将被提炼代码中需要读取的局部变量,当作参数传给目标
范例:
源代码
private Vector _orders; private String _name; void printOwing(){ Enumeration e = _orders.elements(); double outstanding = 0.0; //print banner System.out.println("****************************"); System.out.println("*******Customer Owes********"); System.out.println("****************************"); //calculate outstanding while (e.hasMoreElements()){ Order each = (Order)e.nextElement(); outstanding += each.getAmount(); } //print details System.out.println("name:"+_name); System.out.println("amount:"+outstanding); }
重构
private Vector _orders; private String _name; void printOwing(){ /* 无局部变量 */ //print banner printBanner(); /* 有局部变量,并修改 */ //calculate outstanding double outstanding = getOutstanding(); /* 有局部变量:只读 */ //print details printDetails(outstanding); } private double getOutstanding() { Enumeration e = _orders.elements(); //该变量只是简单初始化,如果有其他处理,则需作为参数传进来 double outstanding = 0.0; while (e.hasMoreElements()){ Order each = (Order)e.nextElement(); outstanding += each.getAmount(); } return outstanding; } private void printDetails(double outstanding) { System.out.println("name:"+_name); System.out.println("amount:"+outstanding); } private void printBanner() { System.out.println("****************************"); System.out.println("*******Customer Owes********"); System.out.println("****************************"); }
二、内联函数(Inline Method)
动机:内部代码和函数名一样清晰易懂或者有一群不甚合理的函数(Replace Method with Method Object)
做法:
检查函数,确定它不具多态性
找出这个函数所有被调用点
将这个函数所有被调用点替换为函数本体
范例:
源代码
private int _numberOfLateDeliveries; 4000 int getRating(){ return (moreThanFiveLateDeliveries()) ? 2:1; } boolean moreThanFiveLateDeliveries(){ return _numberOfLateDeliveries>5; }
重构
private int _numberOfLateDeliveries; int getRating(){ return (_numberOfLateDeliveries > 5) ? 2:1; }
三、内联临时变量(Inline Temp)
动机:临时变量妨碍其他的重构手法时(如Replace Temp with Query)
做法:
检查给临时变量赋值的语句,确保等号右边的表达式没有副作用
如果这个临时变量未被声明为final,那么将他声明为final(编译检查,该变量是否只赋值一次)
找到所有该临时变量的引用点,修改为表达式,并删除这个临时变量
范例
源代码
public boolean test(){ Order anOrder = new Order(); double basePrice = anOrder.basePrice(); return basePrice>1000; }
重构
public boolean test(){ Order anOrder = new Order(); return anOrder.basePrice() >1000; }
四、以查询取代临时变量(Replace Temp with Query)
动机:其他重构手法难以进行时(如Extract Method)
做法:
找出只被赋值一次的临时变量
声明为final(编译检测一次性)
将这个临时变量的等号右侧提炼到独立函数中
范例:
源代码
private int _quantuty; private int _itemPrice; double getPrice(){ int basePrice = _quantuty*_itemPrice; double discountFactor; if(basePrice>1000) discountFactor = 0.95; else discountFactor = 0.98; return basePrice*discountFactor; }
重构
private int _quantuty; private int _itemPrice; double getPrice(){ double discountFactor; return basePrice() *discountFactor(); } private double discountFactor() { if(basePrice() >1000) return 0.95; else return 0.98; } private int basePrice() { return _quantuty*_itemPrice; }
五、引入解释性变量(Introduce Explaining Variable)
动机:表达式复杂而难以理解时,临时变量可以帮助容易阅读
做法:
声明一个final临时变量,将待分解之复杂表达式中的一部分动作的运算结果赋值给他
将表达式中的"运算结果",替换为上述临时变量
范例:
源代码
private int _quantity; private int _itemPrice; double price(){ //price is base price-quantity discount +shipping return _quantity * _itemPrice-Math.max(0,_quantity-500)*_itemPrice*0.05+Math.min(_quantity*_itemPrice*0.1,100.0); }
重构
private int _quantity; private int _itemPrice; double price(){ //price is base price-quantity discount +shipping final double basePrice = _quantity * _itemPrice; final double quantityDiscount = Math.max(0,_quantity-500)*_itemPrice*0.05; final double shipping = Math.min(basePrice*0.1,100.0); return basePrice-quantityDiscount+shipping; }
六、分解临时变量(Split Temporary Variable)
动机:临时变量被赋值超过一次(除循环和结果收集外)
做法:
在待分解临时变量的声明及其第一次被赋值处,修改其名称
将新的临时变量声明为final
以该临时变量的第二次赋值动作为临界点,修改此前对该临时变量的所有引用点,让他们引用新的临时变量
在第二次赋值处,重新声明原先那个临时变量
重复上述过程,直到临时变量被赋值一次为止
范例:
源代码
private double _primaryForce; private double _secondaryForce; private double _mass; private int _delay; double getDistanceTravelled(int time){ double result; double acc = _primaryForce/_mass; int primaryTime = Math.min(time,_delay); result = 0.5*acc*primaryTime*primaryTime; int secondaryTime = time - _delay; if(secondaryTime>0){ double primaryVel = acc*_delay; acc = (_primaryForce+_secondaryForce)/_mass; result += primaryVel=secondaryTime+0.5*acc*secondaryTime*secondaryTime; } return result; }
重构
private double _primaryForce; private double _secondaryForce; private double _mass; private int _delay; double getDistanceTravelled(int time){ double result; final double primaryAcc = _primaryForce/_mass; int primaryTime = Math.min(time,_delay); result = 0.5*primaryAcc*primaryTime*primaryTime; int secondaryTime = time - _delay; if(secondaryTime>0){ double primaryVel = primaryAcc*_delay; double secondaryAcc = (_primaryForce+_secondaryForce)/_mass; result += primaryVel=secondaryTime+0.5*secondaryAcc*secondaryTime*secondaryTime; } return result; }
七、以函数对象取代函数(Replace Method With Method Object)
动机:函数中局部变量泛滥,而无法进行Extract Method时
做法:
建立一个新类,根据待处理函数用途,来命名
在新建类中建立final字段,用以保存原先大型函数所在的对象,每个临时变量和参数建立对应的字段保存。
在新类中建立构造函数,接收源对象以及原函数的所有参数作为参数
在新类中建立一个Compute()
将原函数的代码复制到compute()中,如果需要调用源对象的任何函数,通过源对象字段调用
将旧函数的函数体替换为:创建上述新类对象,并调用compute()
范例:
源代码
int gamma(int inputeVal,int quantity,int yearToDate){ int importantValue1 = (inputeVal * quantity)+delta(); int importantValue2 = (importantValue1=yearToDate)+100; if((yearToDate-importantValue1)>100){ importantValue2 -= 20; } int importantValue3 = importantValue2*7; return importantValue3 -2*importantValue1; } public int delta(){ return 0; }
重构
public class ReplaceMethodWithMethodObject { int gamma(int inputeVal,int quantity,int yearToDate){ return new Gamma(this,inputeVal,quantity,yearToDate).compute(); } public int delta(){ return 0; } } class Gamma{ private ReplaceMethodWithMethodObject object; private int inputVal; private int quantity; private int yearToDate; private int importantValue1; private int importantValue2; private int importantValue3; public Gamma(ReplaceMethodWithMethodObject object, int inputVal, int quantity, int yearToDate) { this.object = object; this.inputVal = inputVal; this.quantity = quantity; this.yearToDate = yearToDate; } int compute(){ importantValue1 = (inputVal * quantity)+object.delta(); importantValue2 = (importantValue1=yearToDate)+100; importantThing(); importantValue3 = importantValue2*7; return importantValue3 -2*importantValue1; } private void importantThing() { if((yearToDate-importantValue1)>100){ importantValue2 -= 20; } } }
八、移除对参数的赋值(Remove Assignment To Parameters)
动机:被传入对象指向一个新的对象
做法:
建立临时变量,把带待处理的对象赋值给他
以"对参数的赋值"为界,将其后所有对此参数的引用,全部替换为"对此临时变量的引用"
修改赋值语句,使其改为对新建之临时变量赋值
范例:
源代码
int discount(int inputVal,int quantity,int yearToDate){ if(inputVal>50) inputVal -=2; if(quantity>100) inputVal -=1; if(yearToDate>1000) inputVal -=4; return inputVal; }
重构
int discount(final int inputVal,final int quantity,final int yearToDate){ int result = inputVal; if(inputVal>50) result -=2; if(quantity>100) result -=1; if(yearToDate>1000) result -=4; return result; }
相关文章推荐
- 【转】PHP 杂谈《重构-改善既有代码的设计》之一 重新组织你的函数
- PHP 杂谈《重构-改善既有代码的设计》之一 重新组织你的函数
- 重构改善既有代码的设计--重新组织函数
- PHP 杂谈《重构-改善既有代码的设计》之一 重新组织你的函数
- 重构-改善既有代码的设计:重新组织函数的九种方法(四)
- 重构改善既有代码设计-----重新组织函数
- 2016书单总结--重构改善既有代码的设计--重新组织函数
- PHP 杂谈《重构-改善既有代码的设计》之一 重新组织你的函数
- PHP 杂谈《重构-改善既有代码的设计》之一 重新组织你的函数【链接:http://www.cnblogs.com/baochuan/archive/2012/03/31/2425441.html】
- 重新组织你的函数(读书摘要——重构改善既有代码的设计)
- 代码重构之重新组织函数
- 代码重构-重新组织函数
- 《重构--改善既有代码的设计》--重新组织函数(6)
- PHP 杂谈《重构-改善既有代码的设计》之一 重新组织你的函数
- 重构-改善既有代码的设计:重新组织函数的九种方法(四)
- 重构-改善既有代码的设计:重新组织函数的九种方法(四)
- PHP 杂谈《重构-改善既有代码的设计》之一 重新组织你的函数
- 代码重构(一)重新组织函数
- 重构—改善既有代码的设计006:重新组织你的函数(Composing Methods)
- PHP:《重构-改善既有代码的设计》之一 重新组织你的函数