【发布时间】:2019-02-26 17:17:59
【问题描述】:
我只有一个有很多实例的类。每个实例都是其他几个实例的观察者。同样,每个实例都可以被其他几个实例观察到。
如何避免观察者调用update()的无限循环?
【问题讨论】:
标签: java design-patterns
我只有一个有很多实例的类。每个实例都是其他几个实例的观察者。同样,每个实例都可以被其他几个实例观察到。
如何避免观察者调用update()的无限循环?
【问题讨论】:
标签: java design-patterns
如果你的系统是单线程的,那么你只需要在你的 notify 方法中设置一个守卫:
private boolean _notifying;
public void notify() {
if(_notifying) {
return;
}
_notifying = true;
try {
// ... do notifying here...
} finally {
_notifying = false;
}
}
【讨论】:
您正在寻找的是一种检测循环的图遍历算法。一种简单的方法(仅适用于单线程场景)是保留一个全局/静态计数器,让每个顶级 update() 调用获得一个唯一标识符。然后每个观察者跟踪它是否已经用给定的标识符(ID)处理了更新,在这种情况下忽略它。这意味着您的 update 方法必须使用带有特定更新 ID 号的参数进行扩展。
【讨论】:
好吧,如果您正在定义“事件”对象,您可能会向其中添加已经处理过事件的对象。在这种情况下,如果您关闭循环,您可以退出。在伪代码中
eventFired(Event e)
if (e.hasBeenEvaluatedBy(this)){
return;
}
e.addEvaluator(this);
// Do magic
refire(e);
}
在这种情况下,我们会得到类似的结果: * A 开火。 * B 处理它并将自己添加到列表中 * B 重新触发 * C 处理事件并将自己添加到列表中 * C 重新触发 * A 处理事件并将自己添加到列表中 * 重新触发 * B 捕捉到事件,但已经在列表中。没有重发,无限循环被打破
可以使用 ID 代替指针来避免垃圾收集问题
【讨论】:
让您的观察者将接收到的事件(或其 ID)添加到某个临时存储中,并在收到每个新事件时让他们验证是否将相同的事件保存在存储中。如果是,那么他们不应该处理它。
但是,如果我们尝试解决问题而不是找到合适的解决方法,那么:您的问题是对象 A 可以侦听对象 B,而对象 B 可以同时侦听对象 A(也许有一些中介对象)。恕我直言,这是一个糟糕的设计。
观察者应该用来松耦合,让对象A知道对象B,反之则不然。
如果您的对象 A 和 B 都相互了解,那么我不明白您为什么需要使用观察者。
【讨论】:
一种方法是仅在实际更新某些内容时才触发诸如更新之类的事件。 这种方法的好处是您通常可以减少触发的事件数量(减少工作)并简化代码。 例如
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);
}
}
【讨论】: