## 代码重构之重新组织函数 原

ChinaHYF

• 提炼方法（Extract Method）

1. 动机：

2. 做法以及注意点：

3. 代表性示例：

1. 第一种情况：

``````void printOwing() {
Enumeration enumeration = _orders.elements();
double outstanding = 0.0;

printBaner();

//calculate outstanding
while (enumeration.hasMoreElements()) {
Order each = (Order) enumeration.nextElement();
outstanding += each.getAmount();
}

printDetails(outstanding);
}``````

``````void printOwing() {
printBanner();
double oustanding = getOutstanding();
printDetails(oustanding);
}

double getOutstanding() {
Enumeration enumeration = _orders.elements();
double outstanding = 0.0;

while (enumeration.hasMoreElements()) {
Order each = (Order) enumeration.nextElement();
outstanding += each.getAmount();
}
return outstanding;
}

double getOutstanding() {
Enumeration enumeration = _orders.elements();
double result = 0.0;

while (enumeration.hasMoreElements()) {
Order each = (Order) enumeration.nextElement();
result += each.getAmount();
}
return result;
}``````

2. 第二种情况：

``````void printOwing(double previousAmount) {
Enumeration enumeration = _orders.elements();
double outstanding = previousAmount * 1.2;

printBaner();

//calculate outstanding
while (enumeration.hasMoreElements()) {
Order each = (Order) enumeration.nextElement();
outstanding += each.getAmount();
}

printDetails(outstanding);
}``````

``````void printOwing(double previousAmount) {
double outstanding = previousAmount * 1.2;
printBanner();
outstanding = getOutstanding();
printDetails(outstanding);
}

double getOutstanding(double initialValue) {
double result = initialValue;
Enumeration enumeration = _orders.elements();

while (enumeration.hasMoreElements()) {
Order each = (Order) enumeration.nextElement();
result += each.getAmount();
}
return result;
}

void printOwing(double previousAmount) {
printBanner();
outstanding = getOutstanding(previousAmount * 1.2);
printDetails(outstanding);
}``````
•  内联函数（Inline Method）

1. 动机：

2. 代表性示例：

``````int getRating() {
return (moreThanFiveLateDeliveries()) ? 2 : 1;
}
boolean moreThanFiveLateDeliveries() {
return _numberOfLateDeliveries > 5;
}``````

``````int getRating() {
return (_numberOfLateDeliveries > 5) ? 2 : 1;
}``````
•  内联临时变量（Inline Temp）

1. 动机：

2. 做法以及注意点：

• 已查询替代临时变量（Replace Temp with Query）

1. 动机：

2. 做法以及注意点：

3. 代表性示例：

``````double getPrice() {
int basePrice = _quantity * _itemPrice;
double discountFactor;
if(basePrice > 1000) {
discountFactor = 0.95;
} else {
discountFactor = 0.98;
}
return basePrice * discountFactor;
}``````

``````//首先,先把它们设置成final类型,进行编译,确保它们只是被简单赋值一次
double getPrice() {
final int basePrice = _quantity * _itemPrice;
final double discountFactor;
if(basePrice > 1000) {
discountFactor = 0.95;
} else {
discountFactor = 0.98;
}
return basePrice * discountFactor;
}
//上面操作完之后，编译没有问题的话，接下来提炼赋值动作右侧的表达式
double getPrice() {
final int basePrice = getBasePrice();
final double discountFactor;
if(basePrice > 1000) {
discountFactor = 0.95;
} else {
discountFactor = 0.98;
}
return basePrice * discountFactor;
}

private int getBasePrice() {
return _quantity * _itemPrice;
}``````

接下来,使用 Inline Temp 来进一步重构

``````//basePrice的使用一共有两处，首先替换第一处，然后进行编译测试。
double getPrice() {
final int basePrice = getBasePrice();
final double discountFactor;
if(getBasePrice() > 1000) {
discountFactor = 0.95;
} else {
discountFactor = 0.98;
}
return basePrice * discountFactor;
}

private int getBasePrice() {
return _quantity * _itemPrice;
}
//发现没有问题之后，进行第二处替换,并且可以直接把 basePrice 的声明就去掉了。
double getPrice() {
final double discountFactor;
if(getBasePrice() > 1000) {
discountFactor = 0.95;
} else {
discountFactor = 0.98;
}
return getBasePrice() * discountFactor;
}

private int getBasePrice() {
return _quantity * _itemPrice;
}
//然后，通过类似方法重构 discountFactor
double getPrice() {
return getBasePrice() * getDiscountFactor();
}

private int getDiscountFactor() {
if(getBasePrice() > 1000) {
return 0.95;
} else {
return 0.98;
}
}

private int getBasePrice() {
return _quantity * _itemPrice;
}

``````
• 引入解释性变量（Introduce Explaining Variable）

1. 动机：

2. 做法以及注意点：

3. 代表性示例：

``````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);
}

//先把底价=数量*单价提取到临时变量中,并且有两处使用的地方,逐一替换
double price() {
final double basePrice = _quantity * _itemPrice;
//price is base price - quantity discount + shipping
return basePrice -
Math.max(0, _quantity - 500) * _itemPrice * 0.05 +
Math.min(basePrice * 0.1, 100.0);
}

//将 quantity discount 再提取出来
double price() {
final double basePrice = _quantity * _itemPrice;
final double quantityDiscount = Math.max(0, _quantity - 500) * _itemPrice * 0.05;
//price is base price - quantity discount + shipping
return basePrice -
quantityDiscount +
Math.min(basePrice * 0.1, 100.0);
}

//最后再把运费 shipping 提取出来
double price() {
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);
//price is base price - quantity discount + shipping
return basePrice -
quantityDiscount +
shipping;
}``````

``````double price() {
//price is base price - quantity discount + shipping
return getBasePrice() -
getQuantityDiscount() +
getShipping();
}

private double getBasePrice() {
return _quantity * _itemPrice;
}

private double getQuantityDiscount() {
return Math.max(0, _quantity - 500) * _itemPrice * 0.05;
}

private double getShipping() {
return Math.min(basePrice * 0.1, 100.0);
}``````

• 分解临时变量（Split Temporary Variable）

1. 动机：

2. 做法以及注意点：

3. 代表性示例：

``````//这里是计算一个运动举例。在起点处，静止的物体收到一个初始力的作用而开始运动。一段时间后，第二个力作用于这个五次，让他再次加速。根据牛顿第二定律，计算物体运动的举例
double getDistanceTravelled(int time) {
double result;
double acc = _primaryForce / _mass;
int primaryTime = Math.min(time, _delay);
result = 0.5 * acc * 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;
}``````

``````double getDistanceTravelled(int time) {
double result;
final double primaryAcc = _primaryForce / _mass;
int primaryTime = Math.min(time, _delay);
result = 0.5 * primaryAcc * primaryTime;
int secondaryTime = time - _delay;

if(secondaryTime > 0) {
double primaryVel = primaryAcc * _delay;
final double secondaryAcc = (_primaryForce * secondaryForce) / _mass;
result += primaryVel * secondaryTime + 0.5 * secondaryAcc * secondaryTime * secondaryTime;
}

return result;
}
``````

接下来，还可以继续应用其它重构方法，让方法变得更加易读。

• 移除对参数的赋值（Remove Assignment to Parameters）

1. 动机：

2. 做法以及注意点：

3. 代表性示例：

``````int discount(int inputVal, int quatity, int yearToDate) {
if(inputVal > 50) {
inputVal -= 2;
}
if(quatity > 100) {
inputVal -= 1;
}
if(yearToDate > 10000) {
inputVal -= 4;
}
return inputVal;
}
/************************************************************/
//重构之后
int discount(int inputVal, int quatity, int yearToDate) {
int result = inputVal;
if(inputVal > 50) {
result -= 2;
}
if(quatity > 100) {
result -= 1;
}
if(yearToDate > 10000) {
result -= 4;
}
return result;
}``````

``````/**
* Created by haoyufei on 18/9/16.
*/
public class Test {
public static void main(String[] args) {
int x = 5;
triple(x);
System.out.println("x after triple:" + x);

}
private static void triple(int arg) {
arg = arg * 2;
System.out.println("x in triple:" + arg);
}

}``````

``````/**
* Created by haoyufei on 18/9/16.
*/
public class Test {
public static void main(String[] args) {
Date date1 = new Date("16 Sep 18");
nextDateUpdate(date1);
System.out.println("date1 after nextDate:" + date1);

Date date2 = new Date("16 Sep 18");
nextDateReplace(date2);
System.out.println("date2 after nextDate:" + date2);
}

private static void nextDateUpdate(Date arg) {
arg.setDate(arg.getDate() + 1);
System.out.println("date1 in nextDate:" + arg);
}

private static void nextDateReplace(Date arg) {
arg = new Date(arg.getYear(), arg.getMonth(), arg.getDay() + 1);
System.out.println("date1 in nextDate:" + arg);
}
}``````

• 以方法对象取代方法（Replace Method with Method Object）

1. 动机：

2. 做法以及注意点：

3. 代表性示例：

``````class Account {
int gamma(int inputVal, int quantity, int yearToDate) {
int importantValue1 = (inputVal * quantity) + delta();
int importantValue2 = (inputVal * yearToDate) + 100;
if((yearToDate - importantValue1) > 100) {
importantValue2 -= 20;
}
int importantValue3 = importantValue2 * 7;

return importantValue3 - 2 * importantValue1;
}
}``````

``````声明一个新类，提供一个final字段用来保存源对象
class Gamma{
private final Account _account;
private int inputVal;
private int quantity;
private int yearToDate;
private int importantValue1;
private int importantValue2;
private int importantValue3;

Gamma(Account source, int inputValArg, int quantityArg, int yearToDateArg) {
_account = source;
inputVal = inputValArg;
quantity = quantityArg;
yearToDate = yearToDateArg;
}

int compute() {
importantValue1 = (inputVal * quantity) + _account.delta();
importantValue2 = (inputVal * yearToDate) + 100;

if((yearToDate - importantValue1) > 100) {
importantValue2 -= 20;
}

int importantValue3 = importantValue2 * 7;

return importantValue3 - 2 * importantValue1;
}
}

//修改旧方法,让它将它的工作委托于刚建立的这个方法对象
int gamma(int inputVal, int quantity, int yearToDate) {
return new Gamma(this, inputVal, quantity, yearToDate).compute();
}``````

再之后可以进行其它重构，比如讲compute()方法中的某些部分可以提取出来

``````int compute() {
importantValue1 = (inputVal * quantity) + _account.delta();
importantValue2 = (inputVal * yearToDate) + 100;

importantThing();

int importantValue3 = importantValue2 * 7;

return importantValue3 - 2 * importantValue1;
}

void importantThing() {
if((yearToDate - importantValue1) > 100) {
importantValue2 -= 20;
}
}``````
• 替换算法（Substitute Algorithm）

1. 整理方法命名规则以及常见词汇查找文档或者规范，结合阿里的规范

### ChinaHYF

【原创】《重构》读书笔记

pandudu
2015/12/23
54
1
[读书]读《重构-改善既有代码的设计》

zemel
2016/03/07
6
0
Introduce Parameter Object (引入参数对象)

Summary： 某些参数总是很自然地同时出现。以一个对象取代这些参数。 动机: 你经常会看到特定的一组参数总是一起被传递。可能有好几个函数都使用这一组参数，这些函数可能隶属于同一个类，也...

2014/04/09
0
0

zhchl2010
2015/12/24
107
0

1.写烂代码很容易 刚入程序员这行的时候经常听到一个观点：你要把精力放在ABCD（需求文档/功能设计/架构设计/理解原理）上，写代码只是把想法翻译成编程语言而已，是一个没什么技术含量的事情...

2016/08/02
21
0

OSChina 周五乱弹 —— 姑娘馋的口水都留下来了。

Osc乱弹歌单（2019）请戳（这里） 【今日歌曲】 @且无需多言 ：分享Fall Out Boy的单曲《Disloyal Order Of Water Buffaloes》 《Disloyal Order Of Water Buffaloes》- Fall Out Boy 手机党...

125
7
vue 对对象的属性进行修改时，不能渲染页面 vue.\$set()

Js_Mei

2
0

max佩恩

12
0
Redux 三大原则

1.单一数据源 在传统的MVC架构中，我们可以根据需要创建无数个Model，而Model之间可以互相监听、触发事件甚至循环或嵌套触发事件，这些在Redux中都是不被允许的。 因为在Redux的思想里，一个...

wenxingjun

9
0

5
0