我只有一个有很多实例的类。每个实例都是其他几个实例的观察者。同样,每个实例都可以被其他几个实例观察到。
如何避免在观察者中调用update()的无限循环?
答案 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);
}
}