06.重构-简化条件表达式

1. 问题及方案

  • 复杂条件逻辑拆分:Decompose(分解) Conditional;
  • 代码多次测试结果相同:Consolidate(合并) Conditional Expression;
  • 条件代码重复:Consolidate Duplicate Conditional Fragments(碎片);
  • “单一出口”特殊情况:Replace Nested Conditional with Guard Clauses;
  • 去除控制标记:Remove Control Flag;
  • switch 语句:Replace Conditional with Polymorphism(多态);
  • 去除 Null 检验:Introduce Null Object;

2. Decompose Conditional(分解条件表达式)

从 if-then-else 中分别提炼到独立函数;

3. Consolidate Conditional Expression(合并条件表达式)

将同样结果的条件测试合并为一个条件表达式,并将这个条件表达式提炼成为一个独立函数。
ps:

  • 类似多个 case 使用同样的代码。
  • 如果你认为这些检查的确需要彼此独立,就可以不要使用该项重构,不过必须表示清楚自己的意义。

4. Consolidate Duplicate Conditional Fragments(合并重复的条件片段)

将重复代码提取到条件表达式之外。

5. Remove Control Flag(移除控制标记)

以 break、continue、return 语句取代控制标记。

6. Replace Nested Conditional with Guard Clauses(以卫语句取代嵌套条件表达式,防御编程)

使用卫语句表现所有特殊情况。
精髓:给某一条分支以特别的重视。

6.1 动机

  • 条件表达式不同形式:
    • 所有分支都是正常行为:使用 if-else;
    • 只有一种是正常行为,其他都是不正常情况:if-return,XXX;
  • 将条件反转,而后使用该重构手法;

6.2 示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void Test(){
if(A==false){
if(B==false){

}else{

}
}
else{
if(B==false){

}else{

}
}
}

改为

1
2
3
4
5
6
7
8
9
10
11
12
13
void Test(){
if(A==false && B==false){
//Do Here
return;
}

if(A==true && B==false){
//
return;
}

...
}

7. Replace Conditional with Polymorphism(以多态取代条件表达式)

将这个条件表达式的每个分支放进一个子类内的覆写函数中,然后将原始函数声明为抽象函数。
ps:多态最根本的好处:根据对象的不同类型(形态)采用不同的行为,而不必编写明显的条件表达式。

7.1 做法

  • 建立继承结构
    • Replace Type Code with Subclasses;
    • Replace Type Code with State/Strategy;

8. Introduce Null Object(引入 Null 对象)

将 null 值替换为 null 对象。
ps

  • 空对象一定是常量,它们的任何成分都不会发生变化。因此,可考虑使用单例模式保证唯一实例。
  • 本质上来说,Null object 模式属于 Special Case 模式。

9. Introduce Assertion(引入断言)

以断言明确表现某些用以对程序状态的假设。
ps

  • 断言是个条件表达式,应该总是为真。若失败,则表示程序员犯错了,所以断言的失败会导致一个非受控异常(unchecked exception)。
  • 断言绝对不能被系统其它部分使用,实际上,最后成品往往需删除断言。
  • 不要滥用断言,请不要使用它来检查“你认为应该为真”的条件,请只是用它来检查“一定必须为真”的条件。
  • 如果断言所指示的约束条件不能满足,代码是否仍能正常运行?若可以,则移除断言。
  • 断言的价值在于:帮助程序员理解代码正确运行的必要条件。

参考

  • 《重构-改善既有代码的设计》(第9章)
坚持原创技术分享,您的支持将鼓励我继续创作!