用子类替换类型代码
什么是类型代码?当您拥有一组数字或字符串,而不是单独的数据类型时,类型代码就会出现,这些数字或字符串构成了某些实体的允许值列表。通常这些特定的数字和字符串通过常量被赋予可理解的名称,这就是为什么这种类型代码会遇到这么多的原因。
问题
您拥有直接影响程序行为的编码类型(此字段的值触发条件中的各种代码)。
解决方案
为编码类型的每个值创建子类。然后从原始类中提取相关行为到这些子类中。用多态性替换控制流代码。


为什么重构
这种重构技术更加复杂用类替换类型代码.
与第一种重构方法一样,您有一组简单的值,它们构成了字段的所有允许值。尽管这些值通常被指定为常量,并且具有易于理解的名称,但使用它们会使您的代码非常容易出错,因为它们仍然是基本类型。例如,您有一个接受参数中的这些值之一的方法。在某一时刻,而不是常数USER_TYPE_ADMIN
用值“ADMIN”
时,该方法接收到相同的小写字符串(“admin”
),这将导致执行作者(你)没有打算的其他内容。
这里我们处理的是控制流代码,比如条件语句如果
,开关
而且吗?
.换句话说,具有编码值的字段(例如$user->type === self::USER_TYPE_ADMIN
)在这些操作符的条件中使用。如果我们要用用类替换类型代码在这里,最好将所有这些控制流结构移到负责数据类型的类中。最终,这当然会创建一个与原始类型非常相似的类型类,也存在相同的问题。
好处
删除控制流代码。而不是笨重的
开关
在原始类中,将代码移动到适当的子类中。这样可以提高对药物的依从性单一责任原则并使程序在一般情况下更具可读性。如果您需要为编码的类型添加一个新值,您所需要做的就是添加一个新的子类,而不涉及现有的代码(参见打开/关闭原则).
通过用类替换类型代码,我们为编程语言级别的方法和字段的类型提示铺平了道路。使用编码类型中包含的简单数字或字符串值是不可能实现的。
什么时候不用
如果已经有了类层次结构,则此技术不适用。在面向对象编程中,不能通过继承来创建双重层次结构。不过,您仍然可以通过组合而不是继承来替换类型代码。要做到这一点,使用将类型代码替换为状态/策略.
如果类型代码的值可以在创建对象后更改,请避免使用这种技术。我们必须以某种方式动态地替换对象本身的类,这是不可能的。不过,在这种情况下,另一种选择也是将类型代码替换为状态/策略.
如何重构
使用自封装字段为包含类型代码的字段创建getter。
将超类构造函数设为private。创建一个静态工厂方法,其参数与超类构造函数相同。它必须包含一个参数,该参数将接受编码类型的起始值。根据这个参数,factory方法将创建各种子类的对象。要做到这一点,在它的代码中,你必须创建一个大的条件,但至少,它将是唯一一个真正必要的条件;否则,子类和多态性也可以。
为编码类型的每个值创建一个唯一的子类。在其中,重新定义编码类型的getter,使其返回编码类型的相应值。
从超类中删除带有类型代码的字段。使它的getter抽象。
当所有可能的东西都被移动了,使用用多态性替换条件型为了一劳永逸地摆脱使用类型代码的条件。