事件引起连锁反应

hoi*_*loi 5 java events swt

我正在使用基于Eclipse RCP的框架,该框架受到低效事件模型的影响.具体而言,控件发出的事件通常是"级联".例如,控件将发出一个COLOR_CHANGED事件,导致父组合将事件传播给兄弟控件,而兄弟控件又决定发出自己的COLOR_CHANGED事件(响应原始事件),从而导致各种各样的连锁反应.我已经分析了应用程序引发超过100,000个事件以呈现一个简单的表单.坦率地说,我不明白它是如何溢出堆栈的.

所以,我正在寻找一种技术或设计模式来防止或减少这种级联行为.我有一些想法,但这不是一个新问题; 对于面向事件的设计,必须有一个"最佳实践".

我的想法:

  • 事件像堆栈跟踪一样运行,因此新事件被链接到它们的原因.这使听众能够忽略源自他们自己的事件.但是,这使我的事件模型变得非常复杂(包装标准SWT事件会很繁琐).更不用说有一些有效的用例,你可能真的想要这种行为.
  • 中央"事件泵"用于引发事件.如果事件在最近n毫秒内具有与先前引发的事件相同的源和有效负载,则将其丢弃.这有望产生兴奋剂效应并防止事件发生级联.显然,我无法控制如何提出SWT/RCP事件,但这些并不是我主要关心的问题.
  • 应输入事件.这似乎是一个倒退,但我认为更细粒度的事件将有助于提高性能.例如,ValidationFailedEvent而不是Event每个人都处理的泛型(然后必须询问它的状态以确定事件类型).

感谢您抽出宝贵时间阅读我的问题.欢迎所有意见/建议.

编辑:感谢pablosaraiva,我读到了责任链,现在有了以下想法:

  • 事件公开一个isHandled属性,如果设置为true,将阻止事件传播.这应该在事件的范围被理解时起作用,但如果事件不能由单个控件"处理"则无效.

Bur*_*ear 1

多年来我尝试过很多不同的方法来解决这个问题。要解决此问题,您可以做的基本事情是让模型仅在事件实际发生变化时才发出事件。这使得模型中每个类的模型稍微复杂一些,但这是我设法使该范例发挥作用的唯一方法。

例如

public void setColor(Color c)
{
   setBackground(c);
   notify(new ColorChangedEvent(this, c));
}
Run Code Online (Sandbox Code Playgroud)

会成为

public void setColour(Color c)
{
    if (!getBackground().equals(c))
    {
       setBackground(c);
       notify(new ColorChangedEvent(this, c));
    }
}
Run Code Online (Sandbox Code Playgroud)

java 中的标准 Observable 类通过“setChanged()”方法支持此操作。

实现这一点的一个稍微简单的方法(但恕我直言,没有那么好)是让“通知”关闭监听,直到它完成通知。也就是说,通知看起来像

private iAmNotifying;
public void notify(Event e) 
{ 
    if (!iAmNotifying)
    {
        iAmNotifying = true;
        doTheActualNotification(e);
        iAmNotifying = false;
    }
}
Run Code Online (Sandbox Code Playgroud)

但这在粒度方面有一些显着的缺点,并且我使用第一种方法取得了更好的成功。