场景:
我有一个容器对象,其中包含各种对象,这些对象都继承自MyContainedObject类。container类的消费者不能直接访问所包含的对象,但我有兴趣知道它们何时发生更改。
设计决策:
在特定类类型上侦听ChangeEvents的最佳方式是什么?我最初的想法是用泛型做点什么。例如,
private TreeMap<Class, ChangeListener> listeners;
public <T extends MyContainedObject> addChangeListenerForObjectsOfType(Class<T> className, ChangeListener listener)
{
listeners.put(className, listener);
}当检测到更改时,容器类将遍历列表并仅通知为该类类型注册的侦听器。
还有其他建议吗?
谢谢。
发布于 2009-06-30 15:26:28
我假设你的TreeMap上的键类型是一个类,而不是一个MyContainedObject。
如果您确实需要侦听特定类类型上的ChangeEvents,并且希望即使在设置侦听器之后也能够向集合中添加元素,那么这似乎是非常合理的。您可能希望为同一类型支持多个侦听器,因此您应该使用多映射类(Google Collections有一些)或对映射中的值使用集合(可能是IdentityHashSet)。
您可能还希望向ChangeListener添加一个类型参数,以便侦听器可以获取已在其上触发事件的对象,该对象已强制转换为适当的类型。
interface ChangeListener<T> {
void changed(T obj, /* whatever */);
}您必须在容器内执行未检查的强制转换才能使其工作,但只要您的侦听器添加方法做了正确的事情,它就应该是安全的。例如:
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建议的,因为它更简单。
发布于 2009-06-30 14:42:36
您也可以简单地让容器代理对所包含的对象的addChangeListener调用。这将允许它们维护它们的侦听器列表,并根据需要触发调用,而不会增加侦听器层次结构中另一个级别的复杂性。
发布于 2009-06-30 14:46:32
这种特定类型的通知方法的一个问题是,客户端可能会注册一个对特定接口何时发生更改感兴趣的侦听器;例如,addChangeListenerForObjectsOfType(Iterable.class)。这意味着您的通知算法不能在侦听器映射中进行简单的查找,除非您显式地阻止了针对接口注册侦听器,而是需要更复杂(效率更低)。
我可能会采用一种不同的方法,而不是让您的实现完全通用。例如,如果您可以确定几个您感兴趣的顶级子类,那么您就可以提供一个更明确的侦听器接口:
public interface Listener {
void classAChanged(ChangeEvent e);
void classBChanged(ChangeEvent e);
void classCChanged(ChangeEvent e);
}我个人更喜欢这样,因为它对于实现接口的程序员来说更加明确,使代码更具可读性。显然,如果您可能在地图中存储数百个不同的子类,那么它可能是不合适的。
您可以更进一步,并提供一个通用的ChangeEvent<T extends MyObject>实现,以避免侦听器回调方法中的向下转换。
https://stackoverflow.com/questions/1063956
复制相似问题