Summary: 你有一个类型码,它会影响类的行为,但你没法经过继承手法消除它。以状态对象取代类型码。 java
动机:算法
本项重构和Replace Type Code with Subclasses很类似,但若是“类型码的值在对象生命期中发生变化”或“其余缘由使得宿主类不能被继承”,你也可使用本重构。本重构使用State模式或Strategy模式。函数
State模式和Strategy模式很是类似,所以不管你选择其中哪种,重构过程都是相同的。“选择哪个模式”并不是问题关键所在,你只须要选择更适合特定情境的模式就好了。若是你打算在本项重构完成以后再以Replace Conditional with Polymorphism简化一个算法,那么选择Strategy模式比较合适;若是你打算搬移与状态相关的数据,并且你把新建对象视为一种变迁状态,就应该选择使用State模式。测试
作法:spa
1.使用Self Encapsulate Field将类型码自我封装起来。code
2.新建一个类,根据类型码的用途为它命名。这就是一个状态对象。对象
3.为这个新类添加子类,每一个子类对应一种类型码。继承
à比起逐一添加,一次性加入全部必要的子类可能更简单些。get
4.在超类中创建一个抽象的查询函数,用以返回类型码。在每一个子类中覆写该函数,返回确切的类型码。it
5.编译。
6.在源类中创建一个字段,用以保存新建的状态对象。
7.调整源类中负责查询类型码的函数,将查询动做转发给状态对象。
8.调整源类中为类型码设值的函数,将一个恰当的状态对象子类赋值给“保存状态对象”的那个字段。
9.编译,测试。
范例:
和上一项重构同样,咱们仍然使用“雇员/薪资”例子。一样的,咱们以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; } }
下面的代码展现使用这些类型码的条件表达式:
int payAmount(){ switch (_type){ case ENGINEER: return _monthlySalary; case SALESMAN: return _monthlySalary + _commission; case MANAGER: return _monthlySalary + _bonus; default: return new RuntimeException("Incorrect Employee"); } }
假设这是一家激情四溢、积极进取的公司,他们能够将表现出色的工程师擢升为经理。所以,对象的类型码是可变的,因此咱们不能使用继承的方式来处理类型码。和之前同样,咱们的第一步仍是使用Self Encapsulate Field将表示类型码的字段自我封装起来:
Employee(int type){ setType(type); } int getType(){ return _type; } void setType(int arg){ _type = type; } int payAmount(){ switch (getType()){ case ENGINEER: return _monthlySalary; case SALESMAN: return _monthlySalary + _commission; case MANAGER: return _monthlySalary + _bonus; default: return new RuntimeException("Incorrect Employee"); } }
如今,咱们须要声明一个状态类。咱们把它声明为一个抽象类,并提供一个抽象函数,用以返回类型码:
abstract class EmployeeType{ abstract int getTypeCode(); }
如今能够开始创造子类了:
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; } }
如今进行一次编译。前面所作的修改实在太平淡了。如今咱们开始修改类型码访问函数,实实在在地把这些子类和Employ类联系起来:
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子句创建相应的工厂函数。还能够马上再使用Replace Conditional with Polymorphism,从而将其余的case子句彻底消除。
最后,能够将全部关于类型码和子类的知识都移到新类,并依此结束Replace Type Code with State/Strategy。首先,咱们把类型码的定义复制到EmployeeType去,在其中创建一个工厂函数以生成适当的EmployeeType对象,并调整Employee中为类型码赋值的函数:
class Employee... void setType(int arg){ _type = EmployeeType.newType(arg); } calss 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中的类型码定义,代之以一个纸箱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: return new RuntimeException("Incorrect Employee"); } }
如今,完事具有,能够运用Replace Conditional with Polymorphism来处理payAmount()函数了。