你有一个不可变得type code,它会影响类的行为。

以一个子类取代这个type code。

Replace Type Code with Subclasses

动机

如果一个type code不会影响行为,你可以使用Replace Type Code with Class;但是,如果一个type code会影响行为,最好的办法就是借助多态来处理变化的行为。

一般来说,这种情况的标志就是条件表达式。可能是switch或者if-else。但是,无论哪种形式,都是检查type code,根据不同的值执行不同的动作。这种情况下,你应该使用Replace Conditional with Polymorphism进行重构。为了完成这项重构,首先应该将type code替换为拥有动态行为的继承体系。这样的一个继承体系应该以type code的宿主类为base class,并且针对每一个type code建立一个子类。

为建立这样的继承体系,最简单的方式就是Replace Type Code with Subclasses。以type code的宿主类为base class,针对每种type code建立相应的sub class。但是以下两种情况,你不能这么做:

(1) type code的值在对象创建后发生改变

(2) 不是由于type code的原因,已经有了sub class。

无论是哪种情况,都需要使用Replace Type Code with State/Strategy。

Replace Type Code with Subclasses的主要作用是搭建一个舞台,让Replace Conditional with Polymorphism得以一展身手。如果宿主类没有出现条件表达式,那么Replace Type Code with Class更合适,并且风险也更低。

使用Replace Type Code with Subclasses的另一个原因就是,宿主类中出现了[只与具备特定type code之对象相关的特性],完成本项重构之后,你可以使用Push Down Method 和 Push Down Field将这些特性推到合适的subclass去,以彰显它们[只与特定情况相关]这一事实。

Replace Type Code with Subclasses的好处在于:它把对不同行为的了解,从class用户那儿转移到了class自身,如果需要加入新的行为变化,我只需添加一个subclass就行了。如果没有多态机制,我就必须找到所有条件式,并逐一修改它们。因此,如果未来还有可能加入新行为,这项重构将特别有价值。

作法

1. 用Self Encapsulate Field 将type code自我封装起来

如果type code被传递给构造函数,你就需要将构造函数变成factory method。

2. 为type code的每一个数值建立一个相应的subclass。在每个sub class中覆写type code的取值函数,使其返回相应的type code的值。

这个值被硬编码于return句中(例如:return 1)。这看起来很肮脏,但这只是权宜之计。当所有case子句都被替换后,问题就解决了。

3. 每建立一个新的sub class,编译并测试。

4. 从super class中删掉保存type code的值域,将type code访问函数声明为抽象函数。

5. 编译,测试。

 

我们使用那个无聊且不实际的雇员薪资的例子;

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;
}

第一步是以Self Encapsulate Field 将type code自我封装起来

int getType() {
return _type;
}

由于Employee构造函数接受type code作为一个参数,所以我必须将它替换为一个factory method

Employee create(int type) {
return new Employee(type);
}
private Employee (int type) {
_type = type;
}

现在,我可以先建立一个subclass Engineer。首先,我建立这个subclass,并覆写type code的取值函数。

class Engineer extends Employee {
int getType() {
return Employee.ENGINEER;
}
}

同时我修改factory method,令它返回一个合适的对象。

class Employee
static Employee create(int type) {
if (type == ENGINEER) return new Engineer();
else return new Employee(type);
}

然后,我继续逐一地处理其他type code,直到所有type code都被替换成sub class为止。此时,我就可以移除Employee中保存type code的值域,并将getType()声明为一个抽象函数。现在factory method看起来像这样:

abstract int getType();
static Employee create(int type) {
switch (type) {
case ENGINEER:
return new Engineer();
case SALESMAN:
return new Salesman();
case MANAGER:
return new Manager();
default:
throw new IllegalArgumentException("Incorrect type code
value");
}
}

当然,我总是避免使用switch语句,但这里只有一处用到switch语句,并且只用于决定创建何种对象,这样的switch语句是可以接受的。

很自然的,在建立了这些subclass之后,你就应该使用Push Down Method 和Push Down Field,将[只与特定的雇员相关]的函数和值域推到相关的subclass去。

posted on 2018-02-07 17:27  Sharpest  阅读(297)  评论(0编辑  收藏  举报