重新组织数据之十五 :Replace Type Code with State/Strategy(以State/strategy 取代型别码)
来源:互联网 发布:双程2网络剧百度云盘 编辑:程序博客网 时间:2024/06/05 03:47
你有一个type code ,它会影响class 的行为,但你无法使用subclassing。
以state object (专门用来描述状态的对象)取代type code 。
动机(Motivation)
本项重构和Replace Type Code with Subclasses 很相似,但如果「type code 的值在对象生命期中发生变化」或「其他原因使得宿主类不能被subclassing 」,你也可以使用本重构。本重构使用State 模式或Stategy 模式[Gang of Four]。
State 模式和Stategy 模式非常相似,因此无论你选择其中哪一个,重构过程都是相同的。「选择哪一个模式」并非问题关键所在,你只需要选择更适合特定情境的模式就行了。如果你打算在完成本项重构之后再以 Replace Conditional with Polymorphism 简化一个算法,那么选择Stategy 模式比较合适;如果你打算搬移与状态相关(state-specific)的数据,而且你把新建对象视为一种变迁状态 (changing state),就应该选择使用State 模式。
作法(Mechanics)
范例(Example)
和上一项重构一样,我仍然使用这个既无聊又弱智的「雇员丨薪资」例子。同样地, 我以Employee 表示「雇员」:
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 。我把它声明为一个抽象类(abstract class),并提供一个抽象函数(abstract method)。用以返回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 访问函数(accessors),实实在在地把这些subclasses 和Employee class 联系起来:
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");
}
}
这意味我将在这里拥有一个switch 语句。完成重构之后,这将是代码中惟一的switch 语句,并且只在对象型别发生改变时才会被执行。我也可以运用Replace Constructor with Factory Method 针对不同的case 子句建立相应的factory method 。我还可以立刻再使用Replace Conditional with Polymorphism,从而将其他的case 子句完全消除。
最后,我喜欢将所有关于type code 和subclass 的知识都移到新的class ,并以此结束Replace Type Code with State/Strategy 首先我把type code 的定义拷贝到EmployeeType class 去,在其中建立一个factory method 以生成适当的 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 定义,代之以一个「指向(代表、指涉)Employee 对象」的reference:
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 函数了。
- 重新组织数据之十五 :Replace Type Code with State/Strategy(以State/strategy 取代型别码)
- 重构之4.Replace Type Code with State/Strategy(以State/Strategy取代类型码)
- Replace Type Code with State/Strategy(以State/Strategy取代型别码)
- 8.15 replace type code with state/strategy (以state/strategy取代类型码)
- 重新组织数据之十三 :Replace Type Code with Class(以类取代型别码)
- 重新组织数据之十四 :Replace Type Code with Subclasses(以子类取代型别码)
- Refactoring - replace Switch statement with state/strategy
- 重新组织数据之二 :Replace Data Value with Object(以对象取代数据值)
- 重新组织数据之十二 :Replace Record with Data Class(以数据类取代记录)
- 重新组织数据之五 :Replace Array with Object(以对象取代数组)
- 重新组织数据之十六 :Replace Subclass with Fields(以值域取代子类)
- 重新组织数据之九 :Replace Magic Number with Symbolic Constant(以符号常量/字面常量取代魔法数)
- Replace Type Code with Class(以类取代型别码)
- Replace Type Code with Subclasses(以子类取代型别码)
- 重新组织你的函数之四 :Replace Temp with Query(以查询取代临时变量)
- 重新组织你的函数之八 :Replace Method with Method Object(以函数对象取代函数)
- 重新组织函数--以查询取代临时变量(Replace Temp with Query)
- 重构之2.Replace Type Code with Class(以类取代类型码)
- android AIDL服务
- SIP协议简介
- php文件下载原理
- jQuery 入门教程(42): jQuery UI Tab 示例(二)
- Linux系统启动过程介绍
- 重新组织数据之十五 :Replace Type Code with State/Strategy(以State/strategy 取代型别码)
- BF and IA vulnerabilities in IBM Lotus Domino
- 黑马程序员_Java网络编程概述
- ActiveMQ 无法启动 提示端口被占用
- hibernate中jcs详解
- 历数那些失败的项目(1)---M...
- JM86中帧内帧间模式的选择(1)
- hdu 1077 Catching Fish 计算几何+暴力枚举
- myeclipse 8.6 安装freemarker插件