模式4:Acyclic Relationships

 由  xuchen 发布

模式描述

模块的关系必须是非循环的。

模式具体描述

当在两个系统模块之间定义关系的时候,它们的耦合度会增加。因为模块需要互相协作来完成任务,所以一定程度的耦合是必须的。但是,循环依赖需要避免。如何判定一个依赖是循环的呢?对于一个模块A,将A直接或者间接依赖的所有模块依次加入集合中,如果发现A再次被加入集合,那么说明模块结构中存在循环依赖。 循环关系可以存在两个、三个或者更多个模块之间。大多数中型或者大型应用包括很多模块,所以评估模块结构的循环依赖是很必要的。

有几种方法来解决模块间的循环依赖关系。

  1. 升级(Escalation):将循环依赖的根源移到更高的级别。
  2. 降级(Demotion):将循环依赖的根源移到更低的级别。
  3. 回调(Callback):将循环依赖的根源移出来抽象成一个接口,然后另一个模块来实现这个接口。

结果

循环依赖对可维护性和复用性有很大的不良影响。

  • 循环依赖导致的耦合有严重后果。 两个模块之间存在依赖,会增加变化带来的影响。当两个模块之间存在循环依赖,这种“涟波”影响会急剧增加。改变一个模块可能导致所有依赖模块的改变,进而导致整个应用的巨大“涟波”变化。因此,有循环依赖的模块作为一个整体,在缺少其他模块的情况下,一个模块是不能被复用、部署、维护的。
  • 有直接或者间接循环关系的模块会不可避免地降低复用性。为了使用一个模块,必须同时使用它所依赖的所有模块。最终,循环依赖会降低可测试性因为模块不能被单独测试。
  • 你可以对模块进行分层。循环结构中的循环会使你的应用分层。分层可以使你层次性的构建和实现模块关系。通过创建可以单独验证模块的“测试模块”,分层也可以方便测试。

    1. 升级: 通过升级,我们将循环依赖的根源移到更高层次的模块中。

    2. 降级: 通过降级,我们将循环依赖的根源移动到更低层次的模块中。“降级”正好和“升级”是相对的。下面我们来比较一下“升级”和“降级”。在升级的情况下,管理协作的逻辑被提升到更高层次、当你复用A和B的时候,如果你不想用C,那么就需要另一段代码来管理写作。结果是模块复用性更前但是可用性降低。而对于降级,为了使用A和B,我们必须还要把C部署上。因为我们不需要再考虑下面的协作代码,结果是模块可用性增强但是复用性降低。选择哪一种情况需要根据开发上下文来确定。

    3. 回调: 回调和观察者模型很类似。通过这种方法,我们将依赖的根源抽象成一个借口,然后让另一个模块来实现这个接口。

总结

循环依赖带来的耦合度会降低可读性、复用性,增加整个软件系统的复杂性。如果模块间有循环关系,那么,它们就会表现为一个整体。我们需要把这种循环打破或者把他们划入一个单独的模块。总之,循环依赖是必须要避免的。


Gou Rui 2013-01-29 15:06

依赖无环确实是一个很重要的性质。

顶(0) 踩(0) 回复
查看评论