14

我有一个事件驱动的架构,其中 A 正在等待 B 的更改,B 正在等待 C 的更改,C 正在等待 A 的更改,形成一个循环。

现在,如果 B 发生变化,则 A 向 C 触发一个事件,C 向 B 触发,B 向 B 触发,A 向 C 触发……无限期地触发。

我现在可以更改我的程序以不包含此循环,但我担心我可能会在以后将自己置于一个我无法做到的角落。在设计基于事件的系统时如何防止此类事情发生?

4

5 回答 5

5

这里的每个人似乎都说循环依赖是不好的。这在某种意义上是正确的,我几乎不惜一切代价避免静态循环依赖。您可以通过本博客中所述的控制反转来做到这一点:http: //blog.schauderhaft.de/2011/07/17/break-dependency-cylces/

但是您所描述的不一定是静态循环依赖,而是运行时的依赖。我不完全确定,但我认为在运行时避免循环依赖或多或少是不可能的。但是当然这不应该导致无限循环。为了解决这些问题,我看到了两个半选项

首先是黑客

确保由另一个事件触发的每个事件都引用了原始事件(或关于它的基本信息,如 id)。当你处理一个事件时,确保它不是来自你自己。

优点:易于实施;绝对防止递归

黑客的另一半

如果您正在同步运行,您可以firingEvent在之前设置一个标志并在之后重置它。设置时忽略传入的事件firingEvent

优点:更容易实现;在单线程中运行时绝对防止递归

语义丰富的解决方案

我确信 A 在某个外部触发器上触发的事件和 A 因为 C 触发而触发的事件实际上是两个不同的事件,或者所有三个事件实际上只是一个可能来自尚未确定的源 D 的事件。或者类似的东西。没有信息就无法判断 A、B 和 C 是什么以及它们正在触发什么事件。如果您找到适当的事件,则循环将消失。

优点:设计会更干净,包含更多信息。

于 2012-04-18T14:22:06.203 回答
2

绘制出你的依赖关系。不应该有循环。循环依赖是重组代码的好借口。

它们也可能导致死锁,以防您需要另一个理由来避免它们。

于 2010-09-10T20:34:01.360 回答
2

在设计基于事件的系统时如何防止此类事情发生?

  1. 仅当对象状态真正改变时才引发事件。

  2. 禁止在引发事件时更改对象状态。

于 2015-07-24T17:04:23.380 回答
0

我认为这是一个很好的问题。不幸的是,我自己没有完整的答案,但这篇文章有几个优点:

如何避免观察者模式中的无限循环?

正如其他人所建议的那样,我不认为答案是避免循环依赖。(嗯,这取决于你对“循环依赖”的定义。)像 Java 这样的语言将在编译时使用接口来最小化类型的循环依赖,这通常是一个好主意。例如,MVC模式中的视图类不“依赖”您的应用程序,它只知道名称为 、 等的接口ValueChangedListenerClickListener但这并不能消除运行时对象之间的循环连接,这可能导致事件循环。

正如在另一篇链接文章中提到的那样,UI 工具包中的某些循环会停止,因为如果控制器或模型将视图的值“设置”为等于其当前值的值,则视图不会触发“更改”事件。但在其他情况下,例如当您为更复杂的数据创建自定义视图时,计算当前数据和新数据的相等性可能是不可行的。

于 2012-04-18T13:18:15.447 回答
-3

循环依赖真的很糟糕。在我理解之前,我不得不用 A、B 和 C 的形式写下你的帖子。我认为你应该摆脱它。如果你把自己置于一个角落,它可能比你可能遇到的循环依赖问题要好得多。

你也绝对可以避免这种情况。A、B 和 C 确实是紧密耦合的。我认为你需要重新考虑他们的责任。也许有一个常见的 D 元素可以减轻您的设计压力。

想到的其他东西是架构分层。如果您可以将 A 放在 B 之上,并且需要与 B 交谈的任何人进行沟通以通过 A 并向下层,那么您可能会给自己一个更轻松的时间。同样,我对您的问题了解不多,所以这些只是广泛的建议。

最后一个选项,也是我最不喜欢的,是在三个组件之间传递一条消息。当每一个被访问时,要求每个组件添加到它已经看到的消息的消息中。然后获取消息的下一个组件包含有关谁看到它的信息。有点像报名表。但同样,最不喜欢的。先试试别的。

祝你好运!

于 2010-09-10T21:14:02.897 回答