企业🤖AI智能体构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
### Replace Type Code with State/Strategy(以State/strategy 取代型别码) 你有一个type code ,它会影响class 的行为,但你无法使用subclassing。 以state object (专门用来描述状态的对象)取代type code 。 ![](https://box.kancloud.cn/2016-08-15_57b1b5a9c6380.gif) **动机(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)** - 使用Self-encapsulate Field 将type code 自我封装起来。 - 新建一个class ,根据type code 的用途为它命名。这就是一个state object。 - 为这个新建的class 添加subclass ,每个subclass 对应一种type code 。 - 比起逐一添加,一次性加入所有必要的subclass 可能更简单些。 - 在superclass 中建立一个抽象的查询函数(abstract query ),用以返回type code 。 在每个subclass 中覆写该函数,返回确切的type code 。 - 编译。 - 在source class 中建立一个值域,用以保存新建的state object。 - 调整source class 中负责查询type code 的函数,将查询动作转发给state object 。 - 调整source class 中「为type code 设值」的函数,将一个恰当的state object subclass 赋值给「保存state object」的那个值域。 - 编译,测试。 **范例(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 函数了。