类 之间的循环依赖:它们为什么不好以及如何摆脱它们?
Circular dependencies between classes: why they are bad and how to get rid of them?
我觉得循环依赖(又名循环引用)意味着糟糕的设计并且会损害项目。我怎样才能说服我的队友和我的经理?
我的项目是一团依赖。有没有一种方法可以摆脱错误的依赖,然后保持清晰?
为什么循环依赖 (CiD) 不好?
两个原因:
可维护性。
您希望您的代码是分层的,即您想要一个自上而下的依赖关系图(该图显示所有箭头向下,没有箭头向上)。
如果您有 CiD,则您的代码不是分层的。
为什么分层代码意味着可维护性?因为,每次你改变一个界面
class,你可以确定它下面的任何东西都不会受到影响。这些知识使维护和开发
系统更便宜,更不容易出错。
好消息是,有了像 Visual Studio 这样的现代开发工具,
Eclipse,
NetBeans, 和
IntelliJ,还算可以
轻松为您的项目生成图表。并且,如果还没有工具,则有一个simple trick。
可靠性。
您不希望在生产中出现意外的无限递归。例如,当您的配置想要
记录错误并且您的错误记录器想要从配置中读取日志文件的名称(您的测试将
pass,因为测试环境没有报错)。
(不幸的是,意外的递归可能是
即使没有 CiD 也能开发。)
有好的CiD吗?
一些 CiD 是有效的、有用的,并且不影响可维护性或可靠性:字符串和对象、文件和文件夹、节点和边缘。通常,这样的圈子位于一个包内,不会导致包之间的循环依赖。
如何检测包裹 CiD?
您可以在依赖关系图中直观地检测 CiD(请参阅上面生成工具的链接)。
如果您的项目很大,或者您想持续监视 CiD,那么实现一个工具很简单,它使用
反射来检测 CiD(遍历 classes 或包深度优先并在第一个反向引用处停止)。
请注意,如果一个包在另一个包中声明,这并不意味着它们相互依赖,除非它们中的 classes 相互引用。
我的项目是一团乱麻。有修复方法吗?
就在这里。以下是步骤:
设计所需的结构。
一个。创建现有包的简单列表,如下所示:
如果您的包结构是分层的,请将其展平,并且不要忘记根包。
b。整理包裹。
重新排序列表,使具有较低抽象级别的包更接近底部,而具有
更高的抽象级别更接近顶部。
如果一个包包含 class 低抽象级别和高抽象级别,您可能希望将此包分成两部分。
如果您的包裹太多,请先将它们分成几层,对这些层进行排序,然后对这些层内的包裹进行排序。
这一步应该会产生你想要的包顺序,你希望依赖关系下降而不是上升。
c。以相同的方式在包中组织 classes。
使过程可衡量。
测量到所需结构的距离,以便在接近目标时看到进度。
对于每个 class,计算错误依赖项的数量(依赖项向上)。这些数字的总和将
成为你的指标。最后,它将为零。
设置监控以检测新的错误依赖项。你想在你的队友(和你自己)之前阻止他们
即将检查另一个错误的依赖项。
错误的依赖一一解决。通常从底部到顶部更容易,因为你会想要澄清
首先是基础知识。
这些提示可能会有所帮助:
A. 你有一个“死星”或“上帝对象”,即一个被 classes 知道的对象。在
换句话说,这样的 class 是许多循环依赖的一部分,这可能导致每个循环的依赖
class 几乎每隔 class.
解决方案:
大多数死星可以通过将它们分成两个(或更多)class 来解决,其中一个 class 仅包含
状态和非常基本的操作,另一个 class 包含高级操作(通常第二个 class 是静态的)。
B. 您在 class 之间没有圆圈,只是在包之间。
解决方案:
考虑将一些 classes 移动到其他软件包。
C. 你有一个 class 使用上层 class 的一些方法,但不拥有它的实例化。
解决方案:
使用回调接口或回调方法(模式观察者)。
D. 你有两个 classes 相互创建并使用彼此的方法。
解决方案:
- 将class合并为一个class。
- 将 classes 放入一个包中,并将它们的关系声明为良好的 CiD。
- 为 class 之一创建工厂 class 和接口。
如何保持项目的清晰度?
如果你有一个小团队和一个小项目,简单地向你的队友解释规则,偶尔检查一下图表。
如果项目又大又复杂,你应该建立一个流程,每次有人来的时候都会收到提醒或拒绝
编译或检查错误的依赖项。
首先,当您的项目非常简单时,反模式设计不会造成问题,它确实会让事情变得更容易。它只会在项目变得复杂时出现问题。选择点来平衡容易和正确是设计的一部分。说服别人总是需要一个真正的错误。
简而言之,为了处理循环依赖,你总是需要将一个与多任务分开。例如:enter image description here
原则是让每个单位专注于它的核心业务或服务。如果你有一个圆圈,有时意味着你制作了一个具有多核心业务的单元。但实际上总是有矿工周期,因为真正的业务流程是这样的。与单元核心无关的可以。
顺便说一句,有人可以帮我内嵌图片吗?谢谢
我觉得循环依赖(又名循环引用)意味着糟糕的设计并且会损害项目。我怎样才能说服我的队友和我的经理?
我的项目是一团依赖。有没有一种方法可以摆脱错误的依赖,然后保持清晰?
为什么循环依赖 (CiD) 不好?
两个原因:
可维护性。
您希望您的代码是分层的,即您想要一个自上而下的依赖关系图(该图显示所有箭头向下,没有箭头向上)。 如果您有 CiD,则您的代码不是分层的。
为什么分层代码意味着可维护性?因为,每次你改变一个界面 class,你可以确定它下面的任何东西都不会受到影响。这些知识使维护和开发 系统更便宜,更不容易出错。
好消息是,有了像 Visual Studio 这样的现代开发工具, Eclipse, NetBeans, 和 IntelliJ,还算可以 轻松为您的项目生成图表。并且,如果还没有工具,则有一个simple trick。
可靠性。
您不希望在生产中出现意外的无限递归。例如,当您的配置想要 记录错误并且您的错误记录器想要从配置中读取日志文件的名称(您的测试将 pass,因为测试环境没有报错)。 (不幸的是,意外的递归可能是 即使没有 CiD 也能开发。)
有好的CiD吗?
一些 CiD 是有效的、有用的,并且不影响可维护性或可靠性:字符串和对象、文件和文件夹、节点和边缘。通常,这样的圈子位于一个包内,不会导致包之间的循环依赖。
如何检测包裹 CiD?
您可以在依赖关系图中直观地检测 CiD(请参阅上面生成工具的链接)。
如果您的项目很大,或者您想持续监视 CiD,那么实现一个工具很简单,它使用 反射来检测 CiD(遍历 classes 或包深度优先并在第一个反向引用处停止)。
请注意,如果一个包在另一个包中声明,这并不意味着它们相互依赖,除非它们中的 classes 相互引用。
我的项目是一团乱麻。有修复方法吗?
设计所需的结构。
一个。创建现有包的简单列表,如下所示:
如果您的包结构是分层的,请将其展平,并且不要忘记根包。
b。整理包裹。
重新排序列表,使具有较低抽象级别的包更接近底部,而具有 更高的抽象级别更接近顶部。 如果一个包包含 class 低抽象级别和高抽象级别,您可能希望将此包分成两部分。如果您的包裹太多,请先将它们分成几层,对这些层进行排序,然后对这些层内的包裹进行排序。 这一步应该会产生你想要的包顺序,你希望依赖关系下降而不是上升。
c。以相同的方式在包中组织 classes。
使过程可衡量。
测量到所需结构的距离,以便在接近目标时看到进度。 对于每个 class,计算错误依赖项的数量(依赖项向上)。这些数字的总和将 成为你的指标。最后,它将为零。
设置监控以检测新的错误依赖项。你想在你的队友(和你自己)之前阻止他们 即将检查另一个错误的依赖项。错误的依赖一一解决。通常从底部到顶部更容易,因为你会想要澄清 首先是基础知识。
这些提示可能会有所帮助:
A. 你有一个“死星”或“上帝对象”,即一个被 classes 知道的对象。在 换句话说,这样的 class 是许多循环依赖的一部分,这可能导致每个循环的依赖 class 几乎每隔 class.
解决方案:
大多数死星可以通过将它们分成两个(或更多)class 来解决,其中一个 class 仅包含 状态和非常基本的操作,另一个 class 包含高级操作(通常第二个 class 是静态的)。B. 您在 class 之间没有圆圈,只是在包之间。
解决方案:
考虑将一些 classes 移动到其他软件包。C. 你有一个 class 使用上层 class 的一些方法,但不拥有它的实例化。
解决方案:
使用回调接口或回调方法(模式观察者)。D. 你有两个 classes 相互创建并使用彼此的方法。
解决方案:
- 将class合并为一个class。
- 将 classes 放入一个包中,并将它们的关系声明为良好的 CiD。
- 为 class 之一创建工厂 class 和接口。
如何保持项目的清晰度?
如果你有一个小团队和一个小项目,简单地向你的队友解释规则,偶尔检查一下图表。
如果项目又大又复杂,你应该建立一个流程,每次有人来的时候都会收到提醒或拒绝 编译或检查错误的依赖项。
首先,当您的项目非常简单时,反模式设计不会造成问题,它确实会让事情变得更容易。它只会在项目变得复杂时出现问题。选择点来平衡容易和正确是设计的一部分。说服别人总是需要一个真正的错误。
简而言之,为了处理循环依赖,你总是需要将一个与多任务分开。例如:enter image description here
原则是让每个单位专注于它的核心业务或服务。如果你有一个圆圈,有时意味着你制作了一个具有多核心业务的单元。但实际上总是有矿工周期,因为真正的业务流程是这样的。与单元核心无关的可以。
顺便说一句,有人可以帮我内嵌图片吗?谢谢