2009-08-24 63 views
3

如果addListener方法调用时检查重复的注册?如果是这样,发现重复时会发生什么?注册Java事件时,通常允许重复侦听器吗?

final public class exampleCanFire { 
    public void addFooListener(FooListener listener) { 
     // Before adding listener to private list of listeners, should I check for duplicates? 
    } 
} 
+2

尽管我不知道从图书馆设计的角度看,答案是肯定的,图书馆唯一一致的做法是注册所有听众(包括重复内容)?否则,如果两个不同的子系统偶然注册了同一个监听器,那么第一个注销它将会弄乱另一个子系统 - 对吗? – 2009-08-24 09:23:55

+1

它会像收到每个事件两次一样,因为其他人重新注册您的监听器。 – Zed 2009-08-24 09:26:07

+0

@Zed:是的,但我认为那是不小心组合了两个子系统的人的错。它必须是组合无关“对等”子系统以了解它们将如何相互作用的人的责任 - 因为替代方案是让每个子系统知道如何与当前存在或可能存在的每个其他无关“对等”子系统交互未来,这是不可行的。 – 2009-08-24 11:22:04

回答

4

我的选择是将它们存储在一个List,而不是重复检查。这种方法的一些优点:

  • 监听器以确定性的顺序通知,并可能将事件标记为“消耗”,导致它们不传播给后续监听器。
  • 人们可以使用CopyOnWriteArrayList实现,它允许听众没有飞出ConcurrentModificationException通知回调过程中,除去本身(这是非常重要,是编写面向事件的代码时,一个典型的疑难杂症)。
+1

对于'CopyOnWriteArrayList' +1。 – Bombe 2009-08-24 09:39:02

+0

第一点是完全有效的,但在第二点上,现在也有可用的CopyOnWriteArraySet,它可能会用于替代。但是,使用列表仍然可能是最好的选择,确保没有注册重复的监听器应该由客户端提供 – 2014-06-30 13:03:46

3

我不认为有检测重复侦听器的指定行为。我会说,除非你正在编写一个事件处理框架,否则最好不要麻烦检查。如果一个类将自己注册为侦听器两次,那么它就是调用代码中的错误,而不是可观察对象中的错误。

如果你确实想做点什么,我只是建议扔一个IllegalArgumentException,说明你不能注册同一个监听器两次的消息。

0

商店他们在一个组,并传播任何设置的回应是:

Set<FooListener> listeners = new HashSet<FooListener>(); 

public boolean addFooListener(FooListener listener) { 
    return listeners.add(listener); 
} 
0

如果使用列表发现比使用JAVA推荐的方法要慢很多。我的猜测是JAVA的方法有更直接的内存交互,或者什么的。无论如何,我同意j_random_hacker的意思,你应该知道什么时候会发生什么情况,并且随后冒着重复听众混淆其他人的行为的风险,但这就是为什么我们测试我们的程序,是不是;-)