如何避免Observer模式中的无限循环?

时间:2010-03-17 17:54:22

标签: java design-patterns

我只有一个有很多实例的类。每个实例都是其他几个实例的观察者。同样,每个实例都可以被其他几个实例观察到。

如何避免在观察者中调用update()的无限循环?

5 个答案:

答案 0 :(得分:7)

如果您的系统是单线程的,那么您只需要在notify方法中使用一个guard:

private boolean _notifying;

public void notify() {
  if(_notifying) {
    return;
  }
  _notifying = true;
  try {
    // ... do notifying here...
  } finally {
    _notifying = false;
  }
}

答案 1 :(得分:4)

您正在寻找的是一种检测周期的图遍历算法。一种简单的方法(仅适用于单线程场景)是保持全局/静态计数器,让每个顶级update()调用获得唯一标识符。然后,每个观察者跟踪它是否已经使用给定的标识符(ID)处理了更新,并且在这种情况下忽略它。这意味着您的update方法必须使用带有特定更新ID号的参数进行扩展。

答案 2 :(得分:4)

好吧,如果您要定义“事件”对象,您可以添加已处理事件的对象。在这种情况下,如果你关闭循环,你可以退出。在seudo-code

eventFired(Event e)
  if (e.hasBeenEvaluatedBy(this)){
    return;
  }
  e.addEvaluator(this);

  // Do magic

  refire(e);
}

在这种情况下,我们得到类似的东西: *发射一些东西。 * B处理它并将其自身添加到列表中 * B补充 * C处理事件并将其自身添加到列表中 * C补充 *处理事件并将其自身添加到列表中 * A refires * B抓住了这个事件,但已列入名单。没有反思,无限循环破碎

可以使用ID而不是指针来避免垃圾收集问题

答案 3 :(得分:2)

让您的观察者将收到的事件(或其ID)添加到某个临时存储中,当收到每个新事件时,让他们验证是否在存储中保存了相同的事件。如果是,那么他们就不应该处理它。

但是如果我们尝试解决问题而不是找到合适的解决方法那么:你的问题是对象A可以监听对象B,对象B可以同时监听对象A(可能有一些中间人)对象)。这是一个糟糕的设计恕我直言。

应该使用观察者来松散耦合,使对象A了解对象B,反之则不然。

如果你的对象A和B都知道对方,那么我不明白为什么你需要使用观察者。

答案 4 :(得分:0)

一种方法是仅在实际更新某些内容时触发更新等事件。 这种方法的好处是,您通常可以减少触发的事件数量(减少工作量)并简化代码。 e.g。

final Set<String> set = ...

public void onAdded(String string) {
   // is only added once.
   if (set.add(string)) {
       // only notifies once no matter how many times onAdded is 
       // called for this string, recursively or not.
       notifyAdded(string);
   }
}