重新组织你的函数
Extract Method
将一段代码放进一个独立函数中,并让函数名称解释该函数的用途。
void printOwing (double amount) {
printBanner();
//print details
System.out.println("name:" + _name);
System.out.println("amount:" + amount);
}
void printOwing (double amount) {
printBanner();
printDetails(amount);
}
void printDetails(double amount) {
System.out.println("name:" + _name);
System.out.println("amount:" + amount);
}
动机
Extract Method是最常用的重构手法之一。当看见一个过长的函数或者一段需要注释才能让人理解用途的代码,就可以将这段代码放进一个独立函数中。
作法
- 创造一个新函数,根据这个函数的意图来给它命名(以它做什么来命名,而不是以怎样做命名)
- 将提炼出的代码从源函数拷贝到新建的目标函数中
- 仔细检查提炼出的代码,看看其中是否引用了作用域限于源函数的变量(包括局部变量和源函数参数)
- 检查是否有仅用于被提炼码的临时变量。如果有,在目标函数中将它们声明为临时变量
- 检查被提炼码,看看是否有任何局部变量的值被它改变。如果一个临时变量值被修改了,看看是否可以将被提炼码处理为一个查询,并将结果赋值给相关变量。如果很难这样做,或如果被修改的变量不止一个,你就不能仅仅将这段代码原封不动地提炼出来。你可能需要先使用Split Temporary Variable,然后再尝试提炼。也可以使用Replace Temp with Query将临时变量消灭掉
- 将被提炼码中需要读取的局部变量,当作参数传给目标函数
- 处理完所有局部变量之后,进行编译
- 在源函数中,将被提炼码替换为对目标函数的调用
- 编译,测试
范例:无局部变量
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);
}
void printOwing() {
Enumeration e = _orders.elements();
double outstanding = 0.0;
printBanner();
// 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);
}
void printBanner() {
// print banner
System.out.println ("**************************");
System.out.println ("***** Customer Owes ******");
System.out.println ("**************************");
}
范例:有局部变量
void printOwing() {
Enumeration e = _orders.elements();
double outstanding = 0.0;
printBanner();
// 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);
}
void printOwing() {
Enumeration e = _orders.elements();
double outstanding = 0.0;
printBanner();
// calculate outstanding
while (e.hasMoreElements()) {
Order each = (Order) e.nextElement();
outstanding += each.getAmount();
}
printDetails(outstanding);
}
void printDetails (double outstanding) {
System.out.println ("name:" + _name);
System.out.println ("amount" + outstanding);
}
范例:对局部变量再赋值
被赋值的临时变量分两种情况。
- 较简单的情况是:这个变量只在被提炼码区段中使用。如果是,你可以将这个临时变量的声明式移到被提炼码中,然后一起提炼出去。
- 另一种情况是:被提炼码之外也使用了这个变量。这又分两种情况:如果这个变量在被提炼码之后未再被使用,你只需直接在目标函数中修改它就可以了;如果被提炼码之后的代码还使用了这个变量,你就需要让目标函数返回该变量改变后的值。
void printOwing() {
Enumeration e = _orders.elements();
double outstanding = 0.0;
printBanner();
// calculate outstanding
while (e.hasMoreElements()) {
Order each = (Order) e.nextElement();
outstanding += each.getAmount();
}
printDetails(outstanding);
}
void printOwing() {
printBanner();
double outstanding = getOutstanding();
printDetails(outstanding);
}
double getOutstanding() {
Enumeration e = _orders.elements();
double outstanding = 0.0;
while (e.hasMoreElements()) {
Order each = (Order) e.nextElement();
outstanding += each.getAmount();
}
return outstanding;
}
double getOutstanding() {
Enumeration e = _orders.elements();
double result = 0.0;
while (e.hasMoreElements()) {
Order each = (Order) e.nextElement();
result = each.getAmount();
}
return result;
}
另外一种情况:
void printOwing(double previousAmount) {
Enumeration e = _orders.elements();
double outstanding = previousAmount * 1.2;
printBanner();
// calculate outstanding
while (e.hasMoreElements()) {
Order each = (Order) e.nextElement();
outstanding += each.getAmount();
}
printDetails(outstanding);
}
void printOwing(double previousAmount) {
double outstanding = previousAmount * 1.2;
printBanner();
outstanding = getOutstanding(outstanding);
printDetails(outstanding);
}
double getOutstanding(double initialValue) {
double result = initialValue;
Enumeration e = _orders.elements();
while (e.hasMoreElements()) {
Order each = (Order) e.nextElement();
result += each.getAmount();
}
return result;
}
void printOwing(double previousAmount) {
printBanner();
double outstanding = getOutstanding(previousAmount * 1.2);
printDetails(outstanding);
}