首页 > 代码库 > 类级的重构

类级的重构

一、类实现的重构

  1.将值对象转化为引用对象:

    如果发现自己创建并维护着多个一模一样的大型复杂对象,请改变对这些对象的引用方式。

    即仅仅保存着一份主拷贝(值对象),然后其他地方使用对该对象的引用(引用对象)。

  2.将引用对象转化为值对象:

    如果看到自己对某个小型的简单对象进行了多次引用操作,请将这些对象都设置为值对象。

  3.用数据初始化替代虚函数:

    如果有一组派生类,差别仅仅是虚函数返回的常量不同。与其在派生类覆盖成员函数,不如

    让派生类在初始化时设定适当的常量值,然后使用基类中的通用代码处理这些值。

  4.改变成员函数或成员数据的位置:

    请考虑对类的继承体系做出修改。这些修改通常可以减少派生类的重复工作:

    1)将子程序上移到基类中。

    2)将成员上移到基类中。

    3)将构造函数的部分代码上移到基类中。

    4)对派生类进行特殊化,即下移到派生类中。    

  5.将特殊代码提取为派生类:

    如果某类里的一部分代码仅仅被其部分实例所使用,应该把这部分特殊的代码放到其派生类中。

  6.将相似的代码结合起来放置到基类中:

    如果两个派生类有相似的代码,将这些代码结合起来并放到基类中。

二、类接口的重构

  1.将成员函数放到另一个类中:

    在目标类中创建一个新的成员函数,然后从原类中将函数体移到目标类中,然后在旧的成员函数中调用新的成员函数。

  2.将一个类变成两个类

    如果一个类同时具备了两种或更多的截然不同的功能,请把这样的类转化为多个类,使得每个类完成一种明确定义的功能。

  3.删除类:

    如果某个类无所事事,就应该把该类的代码放到与所完成功能关系更为密切的另一个类中,然后把这个类删掉。

  4.去除委托关系:

    有时类A调用了类B和类C,而实际上类A只应该调用类B,而B类应该调用类C。在这种情况下就当考虑A对B的接口抽象

    是否合适。如果应该由B负责调用C,那么就应该只有B调用C。

  5.去掉中间人:

    如果存在类A调用类B,类B调用类C的情况,有时让类A直接调用类C会更好。是否应当去掉类B,取决于怎么做才能最好

    地维护类B接口的完整性。

  6.用委托代替继承:

    如果某类需要用到另一个类,但又打算获取对该类接口更多的控制权,那么可以让基类成为原派生类的一个成员,并公开它

    的一组成员函数,以完成一种内聚的抽象。

  7.用继承代替委托:

    如果某个类公开了委托类(成员类)所有的成员函数,那么该类应该从委托类继承而来,而不是使用该类。

  8.引入外部的成员函数:

    如果一个客户类需要被调用类的某个额外的成员函数,而你又无法去修改被调用类,那么可以通过在客户类中创建新成员函数

    方式来提供此功能。

  9.引入拓展类:

    如果一个类需要多个额外的成员函数,你同样无法修改该类,你可以创建一个新类。该类包括了原类的功能以及新增加的功能。

    要实现这点,你既可以通过从原类派生新类然后添加新的成员函数,也可以将原类进行包装,使新类调用所需要的成员函数。

  10.对暴露在外的成员变量进行封装:

    如果数据成员是公用的,请将其改为私用,然后通过成员函数来访问该数据成员的值。

  11.对于不能修改的类成员,删除相关的Set()成员函数:

    如果某个成员在对象创建之时被设值,之后便不能修改,那么就应该在对象的构造函数中对该成员初始化,而不是使用可能产生

    误导的Set()成员函数。

  12.隐藏那些不会在类之外被用到的成员函数:

    如果没有某个成员函数,类的接口更能呈现出内聚性,那就应该隐藏这个成员函数。

  13.封装不使用的成员函数:

    如果发现自己往往只使用类接口的一部分,那么就为类创建新的接口,仅仅把那些必须的成员函数暴露给类的外部。需要注意,

    新的接口应该为类提供一致的抽象。

  14.合并那些实现非常类似的基类和派生类:    

    如果派生类并未提供更多的特殊化,那么就应该把它合并回基类中。

类级的重构