一、类实现的重构
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.合并那些实现非常类似的基类和派生类:
如果派生类并未提供更多的特殊化,那么就应该把它合并回基类中。