观察者设计模式
在观察者设计模式中,主体通过调用每个观察者的 update() 操作来通知所有观察者。这样做的一种方法是,
void notify() {
for (observer: observers) {
observer.update(this);
}
}
但这里的问题是每个观察者都按顺序更新,并且观察者的更新操作可能不会被调用,直到更新之前的所有观察者。如果有一个观察者有一个无限循环来更新,那么它之后的所有观察者将永远不会被通知。
问题:
- 有办法解决这个问题吗?
- 如果是的话,什么是一个很好的例子?
In the Observer Design Pattern, the subject notifies all observers by calling the update()
operation of each observer. One way of doing this is
void notify() {
for (observer: observers) {
observer.update(this);
}
}
But the problem here is each observer is updated in a sequence and update operation for an observer might not be called till all the observers before it is updated. If there is an observer that has an infinite loop for update then all the observer after it will never be notified.
Question:
- Is there a way to get around this problem?
- If so what would be a good example?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
问题在于无限循环,而不是一个接一个的通知。
如果您希望同时更新事物,则需要在不同的线程上触发事物 - 在这种情况下,每个侦听器都需要与其他侦听器同步才能访问触发事件的对象。
抱怨一个无限循环阻止其他更新发生就像抱怨获取一个锁然后进入无限循环阻止其他人访问锁定的对象 - 问题在于无限循环,而不是锁管理器。
The problem is the infinite loop, not the one-after-the-other notifications.
If you wanted things to update concurrently, you'd need to fire things off on different threads - in which case, each listener would need to synchronize with the others in order to access the object that fired the event.
Complaining about one infinite loop stopping other updates from happening is like complaining that taking a lock and then going into an infinite loop stops others from accessing the locked object - the problem is the infinite loop, not the lock manager.
经典的设计模式不涉及并行性和线程。您必须为 N 个观察者生成 N 个线程。但要小心,因为它们与 this 的交互必须以线程安全的方式完成。
Classic design patterns do not involve parallelism and threading. You'd have to spawn N threads for the N observers. Be careful though since their interaction to this will have to be done in a thread safe manner.
您可以使用 java.utils.concurrent.Executors.newFixedThreadPool(int nThreads) 方法,然后调用 invokeAll 方法(也可以使用带有超时的方法来避免无限循环)。
您可以更改循环以添加一个可调用的类,该类采用“observer”和“this”,然后在“call”方法中调用更新方法。
查看此包以了解更多信息信息。
这是我正在谈论的内容的快速而肮脏的实现:
You could make use of the java.utils.concurrent.Executors.newFixedThreadPool(int nThreads) method, then call the invokeAll method (could make use of the one with the timout too to avoid the infinite loop).
You would change your loop to add a class that is Callable that takes the "observer" and the "this" and then call the update method in the "call" method.
Take a look at this package for more info.
This is a quick and dirty implementation of what I was talking about:
我更关心观察者抛出异常,而不是无限循环。您当前的实现不会通知此类事件中的其余观察者。
I'd be more concerned about the observer throwing an exception than about it looping indefinitely. Your current implementation would not notify the remaining observers in such an event.
是的,确保观察者工作正常并及时返回。
当然:
这可以防止给定的循环进入无限循环(如果有意义,它最多应该运行 100 次)
其他机制是在一秒钟内启动新任务线程,但如果它进入无限循环,它最终会消耗所有系统内存:
这将使该观察者实例立即返回,但这只是一种幻觉,你实际上要做的是避免无限循环。
最后,如果您的观察者工作正常,但您只是想尽快通知他们所有人,您可以查看以下相关问题:在所有鼠标事件监听器执行完毕后调用代码。。
Yes, make sure the observer work fine and return in a timely fashion.
Sure:
This one prevent from a given loop to go infinite ( if it makes sense, it should run at most 100 times )
Other mechanism is to start the new task in a second thread, but if it goes into an infinite loop it will eventually consume all the system memory:
That will make the that observer instance to return immediately, but it will be only an illusion, what you have to actually do is to avoid the infinite loop.
Finally, if your observers work fine but you just want to notify them all sooner, you can take a look at this related question: Invoke a code after all mouse event listeners are executed..
所有观察者都会收到通知,这就是您得到的所有保证。
如果你想实现一些奇特的排序,你可以这样做:
这使您远离了经典的观察者模式,因为您的听众是硬连线的,但如果这是您所需要的......那就去做吧!
All observers get notified, that's all the guarantee you get.
If you want to implement some fancy ordering, you can do that:
That takes you away from the classic Observer pattern in that your listeners are hardwired, but if it's what you need... do it!
如果你有一个带有“无限循环”的观察者,它就不再是真正的观察者模式。
您可以向每个观察者触发不同的线程,但必须禁止观察者更改被观察对象的状态。
最简单(也是最愚蠢)的方法就是采用您的示例并将其线程化。
(这是手工编码的,未经测试,可能有一个或五个错误——无论如何,这都是一个坏主意)
这样做的问题是,它会让你的机器变得笨重,因为它必须立即分配一堆新线程。
因此,要解决所有线程同时启动的问题,请使用 ThreadPoolExecutor,因为它会 A) 回收线程,B) 可以限制运行的最大线程数。
在“永远循环”的情况下,这不是确定性的,因为每个永远循环都会永久占用池中的一个线程。
最好的办法是不要让它们永远循环,或者如果必须的话,让它们创建自己的线程。
如果您必须支持无法更改的类,但您可以确定哪些将快速运行,哪些将“永远”运行(用计算机术语来说,我认为这相当于超过一两秒),那么您可以使用类似的循环这个:
嘿,如果它真的“永远循环”,它会为每个通知消耗一个线程吗?听起来您可能需要在设计上花费更多时间。
If you have an observer with an "infinite loop", it's no longer really the observer pattern.
You could fire a different thread to each observer, but the observers MUST be prohibited from changing the state on the observed object.
The simplest (and stupidest) method would simply be to take your example and make it threaded.
(this was coded by hand, is untested and probably has a bug or five--and it's a bad idea anyway)
The problem with this is that it will make your machine chunky since it has to allocate a bunch of new threads at once.
So to fix the problem with all the treads starting at once, use a ThreadPoolExecutor because it will A) recycle threads, and B) can limit the max number of threads running.
This is not deterministic in your case of "Loop forever" since each forever loop will permanently eat one of the threads from your pool.
Your best bet is to not allow them to loop forever, or if they must, have them create their own thread.
If you have to support classes that can't change, but you can identify which will run quickly and which will run "Forever" (in computer terms I think that equates to more than a second or two) then you COULD use a loop like this:
Hey, if it actually "Loops forever", will it consume a thread for every notification? It really sounds like you may have to spend some more time on your design.