重构-改善既有代码的设计读书笔记(九)

本文介绍如何通过卫语句简化嵌套条件表达式,提高代码可读性,并讨论了如何利用多态来重构条件表达式,使得不同类型的对象表现出不同的行为。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

简化条件表达式

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();
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

每天进步一点_点

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值