asa*_*n74 7 java events inheritance listener
我有一个java类,它触发自定义java事件.代码的结构如下:
public class AEvent extends EventObject {
...
}
public interface AListener extends EventListener {
public void event1(AEvent event);
}
public class A {
public synchronized void addAListener(AListener l) {
..
}
public synchronized void removeAListener(AListener l) {
..
}
protected void fireAListenerEvent1(AEvent event) {
..
}
}
Run Code Online (Sandbox Code Playgroud)
一切正常,但我想创建一个新的A子类(称之为B),它可能会触发一个新事件.我正在考虑以下修改:
public class BEvent extends AEvent {
...
}
public interface BListener extends AListener {
public void event2(BEvent event);
}
public class B extends A {
public synchronized void addBListener(BListener l) {
..
}
public synchronized void removeBListener(BListener l) {
..
}
protected void fireBListenerEvent2(AEvent event) {
..
}
}
Run Code Online (Sandbox Code Playgroud)
这是正确的方法吗?我在网上搜索示例,但找不到任何内容.
在这个解决方案中有一些我不喜欢的东西:
BListener有两种方法,一种使用AEvent其他用途BEvent作为参数.B类都有addAListener和addBListener方法.我应该使用私有关键字隐藏addAListener吗?[更新:无法隐藏私人关键字]fireAListenerEvent1和fireBListenerEvent1方法.我正在使用Java 1.5版.
Joa*_*uer 12
我没有看到为什么BListener要扩展的原因AListener.
你真的想强迫每个对B事件感兴趣的人也实施event1()吗?
此外,您无法添加addAListener(),因为派生类无法降低父类中存在的方法的可见性.此外,你不应该,或者你会违反Liskov替换原则(每个B必须能够完成A能做的所有事情).
作为最后一句话,我会使fire*()方法受到保护.通常没有理由让它们公开,减少公共成员的数量可以保持公共界面的清洁.
不要使用继承,它不是你想要的,会导致脆弱和难以改变的设计.组合是一种更灵活,更好的设计方法.始终尝试尽可能精细地设计接口,因为它们不应该被更改为事件.它们是您与系统其余部分的合同.如果需要添加新功能,则第一个选项是向事件添加更多信息.如果这不合适,那么您应该设计一个新的界面来提供该事件.这可以防止必须更改任何不受影响的现有代码.
这是我最喜欢的模式,我相信它通常被称为观察者.
创建一个新的接口,用于定义该事件类型的方法(fooEvent()addFooEventListener()removeFooEventListener()).在生成这些事件的具体类中实现此接口.(我通常称之为SourcesFooEvent,FiresFooEvent,FooEventSource等)
如果你想减少代码的重复就可以构造一个辅助类,它处理听众的注册,将它们存储在集合中,并提供了一个火法用于发布事件.
泛型可以在这里提供帮助.首先,一个通用的监听器接口:
public interface Listener<T> {
void event(T event);
}
Run Code Online (Sandbox Code Playgroud)
接下来,匹配的EventSource接口:
public interface EventSource<T> {
void addListener(Listener<T> listener);
}
Run Code Online (Sandbox Code Playgroud)
最后是一个抽象基类,用于快速构造一个辅助类来处理监听器的注册和事件调度:
public abstract class EventDispatcher<T> {
private List<Listener<T>> listeners = new CopyOnWriteArrayList<T>();
void addListener(Listener<T> listener) {
listeners.add(listener);
}
void removeListener(Listener<T> listener) {
listeners.remove(listener);
}
void fireEvent(T event) {
for (Listener<T> listener : listeners) {
listener.event(event);
}
}
}
Run Code Online (Sandbox Code Playgroud)
您可以通过封装使用抽象的EventDispatcher,允许任何其他类轻松实现EventSource,同时不要求它扩展任何特定的类.
public class Message {
}
public class InBox implements EventSource<Message> {
private final EventDispatcher<Message> dispatcher = new EventDispatcher<Message>();
public void addListener(Listener<Message> listener) {
dispatcher.addListener(listener);
}
public void removeListener(Listener<Message> listener) {
dispatcher.removeListener(listener);
}
public pollForMail() {
// check for new messages here...
// pretend we get a new message...
dispatcher.fireEvent(newMessage);
}
}
Run Code Online (Sandbox Code Playgroud)
希望这说明了类型安全(重要),灵活性和代码重用之间的良好平衡.