Replace Conditional with Polymorphism(以多态取代条件式)

你手上有个条件式,它根据对象型别的不同而选择不同的行为。

将这个条件式的每个分支放进一个subclass内的覆写函数中,然后将原始函数声明为抽象函数。

double getSpeed() {
switch (_type) {
case EUROPEAN:
return getBaseSpeed();
case AFRICAN:
return getBaseSpeed() - getLoadFactor() *
_numberOfCoconuts;
case NORWEGIAN_BLUE:
return (_isNailed) ? 0 : getBaseSpeed(_voltage);
}
throw new RuntimeException ("Should be unreachable");
}

==〉

Replace Conditional with Polymorphism

动机

如果你需要根据不同的对象型别,而采取不同的行为,多态使你不必编写明写的条件式。

如果同一组条件式在程序许多地点出现,那么使用多态的收益是最大的。使用条件式时,如果你想添加一种新型别,就必须查找并更新所有条件式。但如果改用多态,只需建立一个新的subclass,并在其中提供适当的函数就行了。

作法

1. 使用Replace Type Code with Subclasses 或者 Replace Type Code with State/Strategy进行重构,得到一个继承体系

2. 如果要处理的条件式是更大函数中的一部分,首先对条件式进行分析,然后使用Extract Method将它提炼到一个独立函数去。

3. 如果有必要,使用Move Method将条件式放置到继承机构的顶端。

4. 任选一个subclass,在其中建立一个函数,使之覆写superclass中容纳条件式的那个函数,将[与该subclass相关]的条件式分支拷贝到新建函数中,并对它进行适当调整。

为了顺利进行这一步骤,你可能需要将superclass中的某些private值域声明protected。

5. 编译、测试

6. 在superclass中删掉条件式内被拷贝出去的分支。

7. 编译、测试

8. 针对条件式的每个分支,重复上述过程,直到所有分支都被移到subclass内的函数为止。

9. 将superclass之中容纳条件式的函数声明为抽象函数。

 

请允许我继续使用[员工与薪资]这个简单又乏味的例子。我的classes是从Replace Type Code with State/Strategy那个例子中拿来的。示意图如下:

员工与薪资

class Employee...
int payAmount() {
switch (getType()) {
case EmployeeType.ENGINEER:
return _monthlySalary;
case EmployeeType.SALESMAN:
return _monthlySalary + _commission;
case EmployeeType.MANAGER:
return _monthlySalary + _bonus;
default:
throw new RuntimeException("Incorrect Employee");
}
}
int getType() {
return _type.getTypeCode();
}
private EmployeeType _type;
abstract class EmployeeType...
abstract int getTypeCode();
class Engineer extends EmployeeType...
int getTypeCode() {
return Employee.ENGINEER;
}
... and other subclasses

switch语句已经被很好的提炼出来,因此我不必费尽再做一遍,不过我需要将它移到EmployeeType class中,因为EmployeeType class才是被subclassing的class。

class EmployeeType...
int payAmount(Employee emp) {
switch (getTypeCode()) {
case ENGINEER:
return emp.getMonthlySalary();
case SALESMAN:
return emp.getMonthlySalary() + emp.getCommission();
case MANAGER:
return emp.getMonthlySalary() + emp.getBonus();
default:
throw new RuntimeException("Incorrect Employee");
}
}

由于我需要Employee class的数据,所以我需要将Employee对象作为参数传递给payAmount()。这些数据中的一部分也许可以移到EmployeeType class中,但那是另一项重构需要关心的问题了。

调整代码使之通过编译,然后我修改Employee中的payAmount()函数,令它委托EmployeeType。

class Employee...
int payAmount() {
return _type.payAmount(this);
}

现在,我可以处理switch语句了。首先我把switch语句中的Engineer 分支拷贝到Engineer class中

class Engineer...
int payAmount(Employee emp) {
return emp.getMonthlySalary();
}

这个新函数覆写了super class中的switch语句之内那个专门处理Engineer的分支,我是个偏执狂,有时我会故意在case子句中放一个陷阱,检查Engineer class是否正常工作:

class EmployeeType...
int payAmount(Employee emp) {
switch (getTypeCode()) {
case ENGINEER:
throw new RuntimeException ("Should be being
overridden");

case SALESMAN:
return emp.getMonthlySalary() + emp.getCommission();
case MANAGER:
return emp.getMonthlySalary() + emp.getBonus();
default:
throw new RuntimeException("Incorrect Employee");
}
}

接下来,我重复上述过程,直到所有分支都被去除为止:

class Salesman...
int payAmount(Employee emp) {
return emp.getMonthlySalary() + emp.getCommission();
}
class Manager...
int payAmount(Employee emp) {
return emp.getMonthlySalary() + emp.getBonus();
}

然后将superclass的payAmount声明为抽象函数:

class EmployeeType...
abstract int payAmount(Employee emp);

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值