Events 事件驱动架构…无限循环

Events 事件驱动架构…无限循环,events,architecture,event-driven-design,Events,Architecture,Event Driven Design,我有一个事件驱动的体系结构,其中A等待B的更改,B等待C的更改,C等待A的更改,形成一个循环 现在,如果B改变了,那么A向C激发一个事件,它向B激发,它向A激发,它向C激发…无限远 我现在可以改变我的程序,不去控制这个循环,但我担心我可能会在以后的某个时候把自己陷入一个无法控制的角落。在设计基于事件的系统时,如何防止此类事情发生?绘制您的依赖关系。不应该有循环。循环依赖是重新组织代码的好借口 它们还可能导致死锁,以防您需要另一个原因来避免死锁。循环依赖关系非常糟糕。我不得不用A、B、C三个字母写

我有一个事件驱动的体系结构,其中A等待B的更改,B等待C的更改,C等待A的更改,形成一个循环

现在,如果B改变了,那么A向C激发一个事件,它向B激发,它向A激发,它向C激发…无限远


我现在可以改变我的程序,不去控制这个循环,但我担心我可能会在以后的某个时候把自己陷入一个无法控制的角落。在设计基于事件的系统时,如何防止此类事情发生?

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


它们还可能导致死锁,以防您需要另一个原因来避免死锁。

循环依赖关系非常糟糕。我不得不用A、B、C三个字母写下你的文章,才让它对我有意义。我想你应该把它处理掉。如果你把自己陷入困境,这可能比你在循环依赖中遇到的问题要好得多

你当然也可以避免这种情况。A、 B和C是紧密耦合的。我认为你需要重新思考他们的责任。也许有一个通用的D元素可以消除很多设计压力

我想到的另一件事是。如果你可以将A层置于B层之上,并要求与B对话的任何人通过A层和B层进行沟通,那么你可能会给自己一个更轻松的时间。再说一次,我对你的问题不太了解,所以这些只是一些宽泛的建议

最后一个选项,也是我最不喜欢的,是在三个组件之间传递消息。在访问每个组件时,要求每个组件将其已看到的消息添加到消息中。然后,获取消息的下一个组件将包含有关谁看到它的信息。有点像一张登记表。但再一次,最不受欢迎。先试试别的


祝你好运

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

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


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

这里的每个人似乎都说循环依赖性是不好的。这在某种意义上是正确的,我试图不惜一切代价避免静态循环依赖。您可以使用本博客中所述的控制反转来实现:

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

首先是黑客

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

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

黑客的另一半

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

赞成:更容易实施;在单个线程中运行时绝对防止递归

语义丰富的解决方案

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

赞成:设计将更干净,包含更多信息

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

  • 仅当对象状态确实发生更改时引发事件

  • 在引发事件时禁止更改对象状态


  • 听起来像是递归。。。你需要一个保护子句/基本用例来停止事件。有趣的是,我遇到了同样的事情。最后,我们不得不重构代码的整个部分。这听起来像是一个完美的应用程序的场景。我认为他说的不是循环依赖,而是一个事件循环。A、 B&C正在监听事件,让我们想象代码通过观察者模式被完美地解包。问题似乎在于,他对代码进行了编程,使一个组件中的更改传播到另一个组件。与代码耦合无关。是的,但是如果您的事件驱动系统不包含在单个服务中呢。例如,如果您正在运行一个微服务体系结构,其中每个服务都拥有自己的数据,并且您正在利用事件源来保持上下文/服务之间的相关数据同步。您不一定知道可能导致循环D的每个处理程序组合: