在类中有一个变量名称,它用来代表不同的类型,不同的类型改变了类不同的行为,以子类取代这个变量。
如果你面对的类型码(变量)不会影响宿主类的行为,可以使用Replace Type Code with Class (218)来处理它们。但如果类型码会影响宿主类的行为,那么最好的办法就是借助多态来处理变化行为。
一般来说,这种情况的标志就是像switch这样的条件表达式。这种条件表达式可能有两种表现形式:switch语句或者if-then-else结构。不论哪种形式,它们都是检查类型码值,并根据不同的值执行不同的动作。
为简单起见,我还是使用那个恼人又不切实际的「雇员/薪资」例。我们以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;}
第一步是以Self-encapsulate Field 将类型码 自我封装起来
int getType() {return _type;
}
由于Employee 构造函数接受类型码 作为一个参数,所以我必须将它替换为一个工厂函数:
//创建对象实际类型static Employee create(int type) {return new Employee(type);}private Employee (int type) {_type = type;}
现在,我可以先建立一个子类Engineer「表示「工程师」。首先我建立这个子类,并在其中覆写类型码 取值函数:
class Engineer extends Employee {int getType() {return Employee.ENGINEER;}}
同时我应该修改工厂函数 ,令它返回一个合适的对象
class Employee// 返回创建的对象类型static Employee create(int type) {if (type == ENGINEER) return new Engineer();else return new Employee(type);}
然后,我继续逐一地处理其他类型码,直到所有类型码都被替换成子类为止。此时我就可以移除Employee中保存类型码的字段,并将getType()声明为一个抽象函数。现在,工厂函数看起来像这样:
// 声明为一个抽象函数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语句是可以接受的。
很自然地,在建立了这些子类之后,你就应该使用Push Down Method (328)和Push Down Field (329),将只与特定种类雇员相关的函数和字段推到相关的子类去。