简化条件表达式
9.5 Replace Nested Conditional with Guard Clauses(以卫语句取代嵌套条件表达式)
函数中的条件逻辑使人难以看清正常的执行路径。使用卫语句表现所有特殊情况。
double getPayAmount(){
double result;
if(idDead) result = deadAmount();
else{
if(idSeparated) result = separatedAmount();
else{
if(isRetired) result = retiredAmount();
else result = normalPayAmount();
}
}
return result;
}
to
double getPayAmount(){
if(isDead) return deadAmount();
if(isSeparated) return separatedAmount();
if(isRetired) return retiredAmount();
return normalPayAmount();
}
9.6 Replace Conditional with Polymorphism(以多态取代条件表达式)
你手上有个条件表达式,它根据对象类型的不同而选择不同的行为。将这个条件表达式的每个分支放进一个子类内的覆写函数中,然后将原始函数声明为抽象函数。
class Employee {
int payAmount(){
switch(getType()){
case EmployeeType.ENGINEER:
return monthlySalary;
case EmployeeType.SALESMAN;
return monthlySalary+commission;
case EmployeeType.MANAGER:
return monthlySalary+bonus;
...
}
}
int getType(){
return type.getTypeCode();
}
private EmployeeType type;
}
abstract class EmployeeType{
abstract int getTypeCode();
}
class Engineer extends EmployeeType{
int getTypeCode(){
return Employee.ENGINEER;
}
}
...
做法:
1、首先使用Replace Type Code with Subclasses(8.14)或者Replace Type Code with State/Strategy(8.15)建立继承体系。如果需要在对象创建好之后修改类型码,或者要重构的类已经有了子类,就得使用后一种重构方式。
2、如果要处理的条件表达式是一个大函数的一部分,需要先对条件表达式进行分析,然后使用Extract Method(6.1)将它提炼到一个独立函数中。
3、如果有必要,使用Move Method(7.1)将条件表达式搬移到继承结构的顶端。
4、任选一个子类,在其中建立一个函数,使之覆写超类中容纳条件表达式的那个函数。将与该子类相关的条件表达式分支复制到新建函数中,并对它进行适当调整。
class Engineer extends EmployeeType{
int payAmount(Employee emp) {
return emp.getMonthlySalary();
}
}
//其他子类类似上面的
...
为了顺利进行这一步,你可能需要将超类中的某些private字段声明为protected。
5、在超类中删掉条件表达式被复制了的分支。
6、重复上述过程,直到所有分支都移到子类的函数中。
7、将超类中的容纳条件表达式的函数声明为抽象函数。
class EmployeeType{
abstract int payAmount(Employee emp);
}
9.7 Introduce Null Object (引入null对象)
你需要再三检查某对象是否为null。将null值替换为null对象
class Site...
Customer getCustomer(){
return customer;
}
Customer customer;
Customer customer = site.getCustomer();
BillingPlan plan;
if(customer == null) plan = BillingPlan.basic();
else plan = Customer.getPlan();
做法:
1、为源类建立一个子类,使其行为就像是源类的null版本。在源类和null子类中都加上isNull()函数,前者的isNull()应该返回false,后者的应该返回true。
class NullCustomer extends Customer{
public boolean isNull(){
return true;
}
}
class Customer...
public boolean isNull(){
return false;
}
protected Customer(){}
static Customer newNull(){
return new NullCustomer();
}
可以试试这个方法:建立一个nullable接口,将isNull()函数放在其中,让源类实现该接口。
2、找出所有“索求源对象却获得一个null”的地方,修改这些地方,使它们改而获得一个空对象。
class Site...
Customer getCustomer(){
return customer == null ? Customer.newNull():customer;
}
3、找出所有“将源对象与null做比较”的地方,修改这些地方,使它们调用isNull()函数。
Customer customer = site.getCustomer();
BillingPlan plan;
if(customer.isNull()) plan = BillingPlan.basic();
else plan = Customer.getPlan();
String customerName;
if(customer.isNull()) customerName = "occupant";
else customerName = customer.getName();
4、找出这样的程序点:如果对象不是null,做A动作;否则做B动作。
5、对应每一个上述地点,在null类中覆写A动作,使其行为和B动作相同。
class NullCustomer...
public String getName(){
return "occupant";
}
6、使用上述被覆写的动作。然后删除“对象是否等于null”的条件测试。
//原来的条件表达式变成了下面的代码
String customerName = customer.getName();