Change Bidirectional Association to Unidirectional 将双向关联改为单向关联
两个类之间有双向关联,但其中一个类如今不再需要另一个类的特性。去除不必要的关联。
动机
双向关联很有用,但你也必须为它付出代价,那就是维护双向连接、确保对象被正确创建和删除而增加的复杂度。而且,由于很多程序员并不习惯使用双向关联,它往往成为错误之源。
大量的双向连接也很容易造成“僵尸对象”:某个对象本来已经该死亡了,却仍然保留在系统中,因为对它的引用还没有完全清除。
此外,双向关联也迫使两个类之间有了依赖:对其中任一个类的任何修改,都可能引发另一个类的变化。如果这两个类位于不同的包,这种依赖就是包与包之间的相依。过多的跨包依赖会造就紧耦合系统,使得任何一点小小改动都可能造成许多无法预知的后果。
只有在真正需要双向关联的时候,才应该使用它。如果发现双向关联不再有存在价值,就应该去掉其中不必要的一条关联。
做法
- 找出保存“你想去除的指针”的字段,检查它的毎一个用户,判断是否可以去除该指针。
- 不但要检查直接访问点,也要检查调用这些直接访问点的函数。
- 考虑有无可能不通过指针取得被引用对象。如果有可能,你就可以对取值函数使用Subsitute Algorithm,从而让客户在没有指针的情况下也可以使用该取值函数。
- 对于使用该字段的所有函数,考虑将被引用对象作为参数传进去。
- 如果客户使用了取值函数,先运用Self Encapsulate Field将待删除字段自我封装起来,然后使用Subsitute Algorithm对付取值函数,令它不再使用该字段。然后编译、测试。
- 如果客户并未使用取值函数,那就直接修改待删除字段的所有被引用点:改以其他途径获得该字段所保存的对象。每次修改后,编译并测试。
- 如果已经没有任何函数使用待删除字段,移除所有对该字段的更新逻辑,然后移除该字段。 ’
- 如果有许多地方对此字段赋值,先运用Self Encapsulate Field使这些地点改用同一个设值函数。编译、测试。而后将这个设值函数的本体清空。 再编译、再测试。如果这些都可行,就可以将此字段和其设值函数,连同对设值函数的所有调用,全部移除。
- 编译,测试。