一、参考资料
- 《重构 2》6.1 提炼函数
- 《重构 2》10.3 以卫语句取代嵌套条件表达式
二、重构步骤 - 以提炼重复计算函数为例子
演示代码
如下代码,存在坏味道
- 充斥着if else
- 重复的new Length()创建
- 重复的参数this.value 和 target_unit
唯一的不同点 仅仅是计算的方式 如 value / 3,value * 12
public Length as(Unit target_unit) {
Length result = this;
if (this.unit == Unit.FOOT) {
if (target_unit == Unit.YARD) {
result = new Length(this.value / 3, target_unit);
} else if (target_unit == Unit.INCH) {
result = new Length(this.value * 12, target_unit);
}
}
if (this.unit == Unit.YARD) {
if (target_unit == Unit.INCH) {
result = new Length(this.value * 36, target_unit);
} else if (target_unit == Unit.FOOT){
result = new Length(this.value * 3, target_unit);
}
}
return result;
}
具体步骤
注:以下只展示最关键的代码,降低认知负载,做了变化的地方,在代码上都会注释
1.提取重复new创建
例如:下面代码中new Length()
为重复创建
public Length as(Unit target) {
// 提取了重复的new创建
Length result = new Length(this.value, target);
if (this.unit == Unit.FOOT) {
if (target == Unit.YARD) {
// 提取了重复的new创建
result = new Length(this.value /3, target);
} else if (target == Unit.INCH) {
// 提取了重复的new创建
result = new Length(this.value * 12, target);
}
}
//省略...,其他代码同理
}
return result;
}
2.提取会变化的信息
例如:下面代码中this.value
是会变化的
public Length as(Unit target) {
// 提取会变化的信息
double value = this.value;
Length result = new Length(value, target);
if (this.unit == Unit.FOOT) {
if (target == Unit.YARD) {
// 提取会变化的信息
value = value / 3;
result = new Length(value, target);
} else if (target == Unit.INCH) {
// 提取会变化的信息
value = value * 12;
result = new Length(value, target);
}
}
//省略...,其他代码同理
return result;
}
3.使用抽取的共有信息,并删除原有信息
例如:下面代码中,共有信息new Length() 和 value
,因为使用了共有信息,此时原有信息result
就没用了
注:当没用引用时,result变量名会变灰,此时可以用 alt + enter,会有个安全删除,选择安全删除,则会吧所有的result都同步删掉
public Length as(Unit target) {
double value = this.value;
if (this.unit == Unit.FOOT) {
if (target == Unit.YARD) {
value = value / 3;
} else if (target == Unit.INCH) {
value = value * 12;
}
}
// 使用抽取出来的信息
return new Length(value, target);
}
4.提取计算函数
- 例如:下面代码,吧获取value的信息,抽取为方法,封装具体实现,这样当阅读这段代码时,不需要了解具体实现,通过方法名就可以知道这是做什么,相比之前,需要去看这段代码是干什么的,可读性更高。
- 建议:在代码中,可以采取抽取方法的方式,对代码的结构进行一个划分,使其可读性更好
- 抽取方法快捷键参考
后继会出文章,讲解,抽取为方法的好处,以及实战
public Length as(Unit target) {
// 提炼函数
double value = getValue(target);
return new Length(value, target);
}
// 提炼函数
private double getValue(Unit target) {
...
}
5.使用卫语句,简化代码逻辑
public Length getValue(Unit target) {
if (this.unit == Unit.FOOT) {
if (target == Unit.YARD) {
// 提前返回,消除else
return this.value / 3;
}
if (target == Unit.INCH) {
// 提前返回,消除else
return this.value * 12;
}
}
//省略...
return this.value;
}