你有一个type code,它会影响class的行为,但你无法使用subclassing.
以state object(专门用来描述状态的对象)取代type code。
动机
本项重构和Replace Type Code with Subclasses很相似。但如果[type code值在对象生命期中发生变化],或者[其他原因使得宿主类不能被subclassing],你也可以使用本重构。本重构使用state模式或Strategy模式。
state模式和Strategy模式非常相似,因此你无论选择其中哪一个,重构过程都是相同的。[选择哪一个模式]并非问题关键所在,你只需要选择更适合特定情境的模式就行了。如果你打算完成本项重构之后再以Replace Conditional with Polymorphism简化一个算法,那么选择Strategy模式比较合适;如果你打算搬移与状态相关的数据,并且认为对象的状态会改变,就应该选择使用State模式。
作法
1. 用Self Encapsulate Field 将type code自我封装起来
2. 新建一个Class,根据type code的用途为它命名,这就是一个state object.
3. 为这个新建的class添加subclass,每个subclass对应一种type code。
比起逐一添加,一次性加入所有必要的subclass可能更简单些。
4. 在super class中建立一个抽象的查询函数,用以返回type code;在每个subclass中覆写该函数,返回确切的type code。
5. 编译
6. 在source class中建立一个值域,用以保存新建的state object。
7. 调整source class中负责查询type code的函数,将查询动作转发给state object。
8. 调整source class中为type code设值的函数,将一个恰当的state object subclass赋值给[保存state object]的那个值域。
9. 编译、测试。
我仍然使用这个既无聊又弱智的[雇员/薪资]例子。
class Employee {
private int _type;
static final int ENGINEER = 0;
static final int SALESMAN = 1;
static final int MANAGER = 2;
Employee (int type) {
_type = type;
}
下面的代码展示这些type code的条件式:
int payAmount() {
switch (_type) {
case ENGINEER:
return _monthlySalary;
case SALESMAN:
return _monthlySalary + _commission;
case MANAGER:
return _monthlySalary + _bonus;
default:
throw new RuntimeException("Incorrect Employee");
}
}
假设这是一家激情四溢、积极进取的公司,他们可以将表现出色的工程师提升为经理。因此对象的type code是可以改变的,所以我不能使用subclassing来处理type code,和以前一样,我的第一步还是使用Self Encapsulate Field 将表示type code的值域自我封装起来
Employee (int type) {
setType (type);
}
int getType() {
return _type;
}
void setType(int arg) {
_type = arg;
}
int payAmount() {
switch (getType()) {
case ENGINEER:
return _monthlySalary;
case SALESMAN:
return _monthlySalary + _commission;
case MANAGER:
return _monthlySalary + _bonus;
default:
throw new RuntimeException("Incorrect Employee");
}
}
现在我需要声明一个state class,我把它声明为一个抽象类,并提供一个抽象函数,用以返回type code:
abstract class EmployeeType {
abstract int getTypeCode();
}
现在,我可以开始创建subclass了。
class Engineer extends EmployeeType {
int getTypeCode () {
return Employee.ENGINEER;
}
}
class Manager extends EmployeeType {
int getTypeCode () {
return Employee.MANAGER;
}
}
class Salesman extends EmployeeType {
int getTypeCode () {
return Employee.SALESMAN;
}
}
现在进行一次编译,前面所做的修改实在太平淡了,即时对我来说也太简单。现在我要修改type code的访问函数,实实在在的把这些subclass和Employee class联系起来
class Employee...
private EmployeeType _type;
int getType() {
return _type.getTypeCode();
}
void setType(int arg) {
switch (arg) {
case ENGINEER:
_type = new Engineer();
break;
case SALESMAN:
_type = new Salesman();
break;
case MANAGER:
_type = new Manager();
break;
default:
throw new IllegalArgumentException("Incorrect Employee
Code");
}
}
这意味我将在这里拥有一个switch语句,完成重构之后,这将是代码中唯一的switch语句。并且只在对象型别发生改变时才会被执行,我可以使用Replace Constructor with Factory Method针对不同的case子句建立相应的factory methods。我还可以立刻再使用Replace Conditional with Polymorphism,从而将其他的case子句全部消除。
最后,我喜欢将所有关于type code和subclass的知识都移到新的class,并以此结束Replace Type Code with State/Strategy。首先我把type code的定义拷贝到EmployeeType class中,在其中建立一个以生成恰当的EmployeeType 对象,并调整Employee class中为type code赋值的函数。
class Employee...
void setType(int arg) {
_type = EmployeeType.newType(arg);
}
class EmployeeType...
static EmployeeType newType(int code) {
switch (code) {
case ENGINEER:
return new Engineer();
case SALESMAN:
return new Salesman();
case MANAGER:
return new Manager();
default:
throw new IllegalArgumentException("Incorrect Employee
Code");
}
}
static final int ENGINEER = 0;
static final int SALESMAN = 1;
static final int MANAGER = 2;
然后,我删掉Employee中的type code定义,代之以一个指向EmployeeType的实例。
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");
}
}
现在,万事俱备,我可以使用Replace Conditional with Polymorphism来处理payAmount函数了。