类之间的循环依赖:它们为什么不好,如何消除它们? [英] Circular dependencies between classes: why they are bad and how to get rid of them?
问题描述
我觉得循环依赖(又称循环引用)意味着糟糕的设计并损害项目。我如何才能说服我的队友和经理?
我的项目是一堆依赖项。有没有一种方法可以消除错误的依赖,然后保持清晰度?
推荐答案
为什么循环依赖(CID)不好?
两个原因:
可维护性。
您希望您的代码是分层的,即您希望有一个自上而下的依赖关系图(该图显示所有箭头向下,没有向上箭头)。 如果您有CID,则您的代码不是分层的。为什么分层代码意味着可维护性?因为,每次更改 类,则可以确保它下面的任何内容都不会受到影响。这些知识使维护和开发 该系统更便宜,更不容易出错。
好消息是,使用像Visual Studio这样的现代开发工具, Eclipse, NetBeans,以及 IntelliJ,相当 很容易为您的项目生成图表。如果还没有工具,则会出现simple trick。可靠性。
您不希望在生产中出现意外的无限递归。例如,当您的配置要 记录一个错误,您的错误记录器希望从配置中读取日志文件的名称(您的测试将 通过,因为在测试环境中没有错误)。 (不幸的是,意外的递归可能是 即使没有CID也可以开发。)
是否有好的CID?
有些CID是有效的、有帮助的,并且不会影响可维护性或可靠性:字符串和对象、文件和文件夹、节点和边缘。通常,这样的循环位于一个包中,不会在包之间形成循环依赖关系。如何检测包CID?
您可以在依赖关系图上直观地检测CID(请参阅上面指向生成工具的链接)。
如果您的项目很大,或者您希望持续监视CID,那么实现一个使用 用于检测CID的反射(深度优先遍历类或包,并在第一个反向引用处停止)。
请注意,如果一个包在另一个包内部声明,这并不意味着它们彼此依赖,除非它们的类相互引用。
我的项目是一堆依赖项。是否有解决此问题的方法?
设计所需的结构。
A.创建现有程序包的普通列表,如下所示:如果您的包结构是分层的,请将其扁平化,并且不要忘记根包。
B.组织包裹。
重新排序列表,以使抽象级别较低的包更接近底部,而具有 抽象级别越高,越接近顶层。 如果包同时包含低抽象级别和高抽象级别的类,您可能希望将该包一分为二。 如果您有太多的包,首先将它们拆分成层,对层进行排序,然后在这些层中对包进行排序。 此步骤应该会产生您想要的包顺序,其中您希望依赖项向下而不是向上。c.以相同方式组织包中的类。
使过程可度量。
测量到所需结构的距离,以便在接近目标时可以看到进度。 对于每个类,统计错误依赖项的数量(指向向上的依赖项)。这些数字的总和将 成为你的衡量标准。最终,它将为零。
/li>
设置监视以检测新的错误依赖项。你想阻止你的队友(和你自己)在他们之前 即将签入另一个错误的依赖项。逐一解析错误依赖。通常,从下到上更容易,正如您想要澄清的那样 基础知识先行。
这些提示可能会有所帮助:
A.您有一个"死星"或"上帝对象",即它所知道的类所知道的对象。 换句话说,这样的类是许多循环依赖的一部分,这些循环依赖可能导致每个循环依赖 几乎所有其他类上都有。
解决方案:
大多数死星可以通过将它们分成两个(或更多)类来解析,其中一个类仅包含 状态和非常基本的操作,另一个类包含高级操作(通常第二个类是静态的)。B.您没有类之间的圆,只是包之间的圆。
解决方案:
考虑将一些类移动到其他包。C.您的类使用了上层类的某些方法,但不拥有其实例化。
D.您有两个相互创建并使用彼此方法的类。
解决方案:
- 将这些类合并为一个类。
- 将类放入一个包中,并将它们的关系声明为良好的CID。
- 为其中一个类创建一个Factory类和接口。
如何保持项目的清晰度?
如果你有一个小团队和一个小项目,只需向你的队友解释规则,并偶尔查看图表。
如果项目又大又复杂,您应该建立一个流程,以便在每次有人 在错误的依赖项中编译或签入。这篇关于类之间的循环依赖:它们为什么不好,如何消除它们?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!