重构数据-Replace Type Code with Subclasses以子类取代类型码十三
迪丽瓦拉
2025-05-31 04:46:48
0

重构数据-Replace Type Code with Subclasses以子类取代类型码十三

1.以子类取代类型码

1.1.使用场景

在类中有一个变量名称,它用来代表不同的类型,不同的类型改变了类不同的行为,以子类取代这个变量。

如果你面对的类型码(变量)不会影响宿主类的行为,可以使用Replace Type Code with Class (218)来处理它们。但如果类型码会影响宿主类的行为,那么最好的办法就是借助多态来处理变化行为。

一般来说,这种情况的标志就是像switch这样的条件表达式。这种条件表达式可能有两种表现形式:switch语句或者if-then-else结构。不论哪种形式,它们都是检查类型码值,并根据不同的值执行不同的动作。

1.2.如何做

  • 使用Self Encapsulate Field (171)将类型码自我封装起来。
  • 如果类型码被传递给构造函数,就需要将构造函数换成工厂函数。
  • 为类型码的每一个数值建立一个相应的子类。在每个子类中覆写类型码的取值函数,使其返回相应的类型码值。
    这个值被硬编码于return句中(例如,return 1)。这看起来很肮脏,但只是权宜之计。当所有case子句都被替换后,问题就解决了。
  • 每建立一个新的子类,编译并测试。
  • 从超类中删掉保存类型码的字段。将类型码访问函数声明为抽象函数。
  • 编译,测试。

1.3.示例

为简单起见,我还是使用那个恼人又不切实际的「雇员/薪资」例。我们以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),将只与特定种类雇员相关的函数和字段推到相关的子类去。

相关内容