您的位置:首页 > 编程语言

《重构改善既有代码的设计》之重构列表--重新组织数据(五)

2012-12-18 11:02 211 查看

十四、Replace Type Code with Subclass(以子类取代类型码)

你有一个不可变的类型码,它会影响类的行为。 以子类取代这个类型码。 动机 如果你面对的类型码不会影响宿主类的行为,可以使用Replace Type Code with Class来处理它们。但如果类型码会影响宿主类的行为,那么最好的办法就是借助多态来处理变化行为。 一般来说,这种情况的标志就是像switch这样的条件表达式。这种条件表达式可能有两种形式:switch语句或者if-else-then结构。不论哪种形式,它们都是检查类型码值,并根据不同的值执行不同的动作。这种情况下,你应该以Replace Conditional with Polymorphism进行重构。单位了能够顺序进行那样的重构,首先应该将类型码替换为可拥有多态行为的继承体系。这样的一个继承体系以类型码的宿主类为基类,并针对每一种类型码各建立一个子类。 为建立这样的继承体系,最简单的办法就是Replace Type Code with Subclass:以类型码的宿主类为基类,并针对每一种类型码建立相应的子类。 但是一下两种情况你不能那么做:(1)类型码值在对象创建之后发生改变(2)由于某些原因,类型码宿主类已经有了子类。如果你恰好面临这两种情况之一,就需要使用Replace Type Code with State/Strategy。 Replace Type Code with Subclass的主要作用就是搭建一个舞台,让Replace Conditional with Polymorphism 得以一展身手。如果宿主类中并没有出现条件表达式,那么Replace Type Code with Class更合适,风险也比较低。 使用Replace Type Code with Subclass的另一个原因就是:宿主类中出现了“只与具备特定类型码之对象关联”的特性。完成本项重构后,你可以使用Push Down Method和Push Down Field将这些特性推到合适的子类去,以彰显它们只与特定情况相关这一事实。 Replace Type Code with Subclass的好处在于:它把“对不同行为的了解”从类用户那儿转移到了类自身。如果需要再加入新的行为变化,只需添加一个子类就行了。如果没有多态机制,就必须找到所有条件表达式,并逐一修改它们。因此,如果未来还有可能加入新行为,这项重构将特别有价值。 做法 1、使用Self Encapsulate Field将类型码自我封装起来。 ? 如果类型码被传递给构造函数,就需要将构造函数换成工厂函数。 2、为类型码的每一个数值建立一个相应的子类。在每个子类中覆写类型码的取值函数,使其返回相应的类型码值。 ? 这个值被硬编码于return语句中。这看起来很肮脏,但只是权宜之计。当所有case子句都被替换后,文体就解决了。 3、每建立一个新的子类,编译并测试。 4、从超类中删掉保存类型码字段。将类型码访问函数声明为抽象函数。 5、编译、测试。

十五、Replace Type Code with State/Strategy (以State/Strategy取代类型码)

你有一个类型码,它会影响类的行为,但你无法通过继承手法消除它。 以状态对象取代类型码。 动机 本项重构和Replace Type Code with Subclass很相似,但如果“类型码的值在对象生命期中发生变化”或“其他原因使得宿主类不能被继承”,你也可以使用本重构。本重构使用State模式或Strategy模式。 State模式或Strategy模式非常相似,因此无论你选择其中哪一个,重构过程都是相同的,“选择哪一模式”并非问题的关键所在,你只需要选择更适合特定情况的模式就可以了。如果你打算再完成本项重构之后再以Replace Conditional with Polymorphism简化一个算法,那么选择Strategy模式比较合适,如果你打算搬移与状态相关的数据,而且你把新对象视为一种变迁状态,就应该选择使用State模式。 做法 1、使用Self Encapsulate Field 将类型码封装起来。 2、新建一个类,根据类型码的用途为它命名。这就是一个状态对象。 3、为这个新类添加子类,每个子类对于一种类型码。 ? 比起逐一添加,一次性加入所有必要的子类可能跟简单些。 4、在超类中建立一个抽象的查询函数,用以返回类型码。在每个子类中覆写该函数,返回确切的类型码。 5、编译。 6、在源类中建立一个字段,用以保存新建的状态对象。 7、调整源类中为类型码设值的函数,将一个恰当的状态对象子类赋值给“保存状态对象”的那个字段。 8、编译、测试。

十六、Replace Subclass with Fields(以字段取代子类)

你的各个子类的唯一差别只在“返回常量数据”的函数身上。 修改这些函数,使它们返回超类中的某个“新增”字段,然后销毁子类。 动机 建立子类的目的,是为了增加新特性或变化其行为。有一种变化行为被称为“常量函数”,它们会返回一个硬编码的值。这东西有其用途:你可以让不同的子类中的同一个访问函数返回不同的值。你可以在超类中将访问函数声明为抽象函数,并在不同的子类中让它返回不同的值。 尽管常量函数有其用途,但若子类中只有常量函数,实在没有足够的存在价值。你可以在超类中设计一个与常量函数返回值相应的字段,从而完全去除这样的子类。如此一来就可以避免因继承而带来的额外复杂性。 做法 1、对所有子类使用Replace Constructor with Factory Method。 2、如果有任何代码直接引用子类,令它改而引用超类。 3、针对每个常量函数,在超类中声明一个final字段。 4、为超类声明一个protected构造函数,用以初始化这些新增字段。 5、新建或修改子类构造函数,是它调用超类的新增构造函数、 6、编译、测试 7、在超类中实现所有常量函数,令它们返回相应字段值,然后将该函数从子类中删掉。 8、每删除一个常量函数,编译并测试。 9、子类中所有的常量函数都被删除后,使用Inline Method将子类构造函数内联到超类的工厂函数中。 10、编译、测试 11、将子类删掉。 12、编译、测试。 13、重复“内联构造函数、删除子类”过程,知道所有子类都被删除。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: