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