本文是在学习中的总结,欢迎转载但请注明出处:http://blog.csdn.net/pistolove/article/details/42214393
在前面的三篇文章中介绍了重构入门篇、代码的坏味道(上)、代码的坏味道(下)。本文将正式开启重构之旅。从本文开始在后续的文章中会陆续介绍92种重构手法,每一种重构手法都会对应于一种代码坏味道。在介绍的过程中,每一种重构手法也将对应一篇文章,可能有的重构手法比较简短,但是为了便于整理还是单独将其列为一篇。(PS:不管怎样,我都会坚持把这些重构手法分享给大家,我想总会有人从中受益,同时也希望对你有所帮助)
下面让我们来学习“提炼函数”这种重构手法吧。
开门见山
发现:你有一段代码可以被组织在一起并独立出来。
解决:将这段代码放进一个独立函数中,并让函数名称解释该函数的用途。
重构前:
public void PrintOwing(double amount) {
printBanner();
// printdetail
System.err.println("name: " + _name);
System.err.println("amount: " + amount);
}
重构后:
public void PrintOwing(double amount) {
printBanner();
printDetails(amount);
}
private void printDetails(double amount) {
System.err.println("name: " + _name);
System.err.println("amount: " + amount);
}
动机
提炼函数是最常用的重构手法之一。当我们看见一个过长的函数或者一段需要注释才能让人理解用途的代码,一般情况下,我们都应该对其进行重构将这段代码放进一个独立的函数中。
我们都喜欢简短而命名良好的函数。原因主要有三个方面:一是如果每个函数的粒度都很小,那么函数被复用的机会就更大;二是这会让高层函数读起来就像一系列注释一样,容易理解;三是如果函数都是细粒度,那么函数的复写也会更加容易。
可能你会问,一个函数多长才算是合适呢?对于重构来说,长度不是问题,关键在于函数名称和函数本题之间的语义距离。如果提炼可以强化代码的清晰度,那么就值得去做,就算函数名称比提炼出来的代码还长也无所谓。
做法
(7)处理完所有局部变量后,进行编译。
(8)编程成功后,在源函数中,将被提炼出的代码段替换为对目标函数的调用。
(9)测试。
示例
A:无局部变量
// 重构前
public void PrintOwing() {
Enumeration e = _orders.elements();
double outstanding = 0.0;
// print banner
System.err.println("************************************");
System.err.println("****************OK******************");
System.err.println("************************************");
// caculate outstanding
while (e.hasMoreElements()) {
Order each = (Order) e.nextElement();
outstanding += each.getAmout();
}
// print details
System.err.println("name: " + _name);
System.err.println("amout: " + outstanding);
}
// 重构后
public void PrintOwing() {
Enumeration e = _orders.elements();
double outstanding = 0.0;
printBanner();
// caculate outstanding
while (e.hasMoreElements()) {
Order each = (Order) e.nextElement();
outstanding += each.getAmout();
}
// print details
System.err.println("name: " + _name);
System.err.println("amout: " + outstanding);
}
private void printBanner() {
// print banner
System.err.println("************************************");
System.err.println("****************OK******************");
System.err.println("************************************");
}
B:有局部变量
// 有局部变量
public void PrintOwing() {
Enumeration e = _orders.elements();
double outstanding = 0.0;
printBanner();
// caculate outstanding
while (e.hasMoreElements()) {
Order each = (Order) e.nextElement();
outstanding += each.getAmout();
}
printDetails(outstanding);
}
private void printDetails(double outstanding) {
System.err.println("name: " + _name);
System.err.println("amout: " + outstanding);
}
C:对局部变量再赋值
// 提炼计算函数
public void PrintOwing() {
printBanner();
double outstanding = getOutstanding();
printDetails(outstanding);
}
private double getOutstanding() {
Enumeration e = _orders.elements();
double outstanding = 0.0;
while (e.hasMoreElements()) {
Order each = (Order) e.nextElement();
outstanding += each.getAmout();
}
return outstanding;
}
private double getOutstanding() {
Enumeration e = _orders.elements();
double result = 0.0;
while (e.hasMoreElements()) {
Order each = (Order) e.nextElement();
result+= each.getAmout();
}
return result;
}
// 有参数 重构前
public void PrintOwing(double previousAmount) {
Enumeration e = _orders.elements();
double outstanding = previousAmount * 1.5;
printBanner();
// caculate outstanding
while (e.hasMoreElements()) {
Order each = (Order) e.nextElement();
result += each.getAmout();
}
printDetails(outstanding);
}
// 重构后
public void PrintOwing(double previousAmount) {
double outstanding = previousAmount * 1.5;
printBanner();
outstanding = getOutstanding(outstanding);
printDetails(outstanding);
}
private double getOutstanding(double initialValue) {
double result = initialValue;
while (e.hasMoreElements()) {
Order each = (Order) e.nextElement();
result += each.getAmout();
}
return result;
}
// 最后的调整
public void PrintOwing(double previousAmount) {
printBanner();
outstanding = getOutstanding(previousAmount * 1.5);
printDetails(outstanding);
}
本文主要介绍了重构手法——提炼函数,针对不同的情况分别作了简单的介绍。本文举得例子都比较简单,对于刚学的人比较容易接受。但是,如果临时变量太多,有时会使得提炼工作举步维艰,这时我们就需要考虑结合其它的重构手法来进行处理。待学习了若干重构手法后,我想如何运用你肯定自然明了。总之,通过对本文的学习,对你多少会有一些帮助,比如对于一段代码只做了一件事情且不受其它代码的影响,那么则可以使用本文的重构手法将其提炼为一个独立的函数等等。