首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Java -通用ChangeListener

Java -通用ChangeListener
EN

Stack Overflow用户
提问于 2009-06-30 14:21:14
回答 4查看 6.4K关注 0票数 4

场景:

我有一个容器对象,其中包含各种对象,这些对象都继承自MyContainedObject类。container类的消费者不能直接访问所包含的对象,但我有兴趣知道它们何时发生更改。

设计决策:

在特定类类型上侦听ChangeEvents的最佳方式是什么?我最初的想法是用泛型做点什么。例如,

代码语言:javascript
复制
private TreeMap<Class, ChangeListener> listeners;

public <T extends MyContainedObject> addChangeListenerForObjectsOfType(Class<T> className, ChangeListener listener)
{
   listeners.put(className, listener);
}

当检测到更改时,容器类将遍历列表并仅通知为该类类型注册的侦听器。

还有其他建议吗?

谢谢。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2009-06-30 15:26:28

我假设你的TreeMap上的键类型是一个类,而不是一个MyContainedObject。

如果您确实需要侦听特定类类型上的ChangeEvents,并且希望即使在设置侦听器之后也能够向集合中添加元素,那么这似乎是非常合理的。您可能希望为同一类型支持多个侦听器,因此您应该使用多映射类(Google Collections有一些)或对映射中的值使用集合(可能是IdentityHashSet)。

您可能还希望向ChangeListener添加一个类型参数,以便侦听器可以获取已在其上触发事件的对象,该对象已强制转换为适当的类型。

代码语言:javascript
复制
interface ChangeListener<T> {
    void changed(T obj, /* whatever */);
}

您必须在容器内执行未检查的强制转换才能使其工作,但只要您的侦听器添加方法做了正确的事情,它就应该是安全的。例如:

代码语言:javascript
复制
public <T extends MyContainedObject> addChangeListener(Class<T> klass,
                                                       ChangeListener<? super T> listener) {
    ...
}    

private <T extends MyContainedObject> Set<ChangeListener<? super T>> getChangeListeners(T obj) {
    Set<ChangeListener<? super T>> result = new IdentityHashSet<ChangeListener<? super T>>();
    for (Map.Entry<Class<? extends MyContainedObject>, Set<ChangeListener<?>>> entry : listeners.entrySet()) {
        if (entry.getKey().isInstance(obj)) {
            // safe because signature of addChangeListener guarantees type match
            @SuppressWarnings("unchecked")
            Set<ChangeListener<? super T>> listeners =
                (Set<ChangeListener<? super T>>) entry.getValue();
            result.addAll(listeners);
        }
    }
    return result;
}

一个小缺点:我会避免使用"className“作为保存类对象的变量的名称。类名是一个字符串,通常是Class.getName()的结果,等等。这有点烦人,但我通常看到的避免"class“是保留字的惯例是将它错误地拼写为"klass”或"cls“。

此外,如果你不需要在添加侦听器后更新集合的能力,那么我会使用akf建议的,因为它更简单。

票数 7
EN

Stack Overflow用户

发布于 2009-06-30 14:42:36

您也可以简单地让容器代理对所包含的对象的addChangeListener调用。这将允许它们维护它们的侦听器列表,并根据需要触发调用,而不会增加侦听器层次结构中另一个级别的复杂性。

票数 1
EN

Stack Overflow用户

发布于 2009-06-30 14:46:32

这种特定类型的通知方法的一个问题是,客户端可能会注册一个对特定接口何时发生更改感兴趣的侦听器;例如,addChangeListenerForObjectsOfType(Iterable.class)。这意味着您的通知算法不能在侦听器映射中进行简单的查找,除非您显式地阻止了针对接口注册侦听器,而是需要更复杂(效率更低)。

我可能会采用一种不同的方法,而不是让您的实现完全通用。例如,如果您可以确定几个您感兴趣的顶级子类,那么您就可以提供一个更明确的侦听器接口:

代码语言:javascript
复制
public interface Listener {
    void classAChanged(ChangeEvent e);
    void classBChanged(ChangeEvent e);
    void classCChanged(ChangeEvent e);
}

我个人更喜欢这样,因为它对于实现接口的程序员来说更加明确,使代码更具可读性。显然,如果您可能在地图中存储数百个不同的子类,那么它可能是不合适的。

您可以更进一步,并提供一个通用的ChangeEvent<T extends MyObject>实现,以避免侦听器回调方法中的向下转换。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/1063956

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档