Java侦听器继承
我有一个触发自定义java事件的java类。该守则的结构如下:Java侦听器继承,java,inheritance,events,listener,Java,Inheritance,Events,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 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
方法。我应该用private关键字隐藏addAListener吗[更新:不可能用私有关键字隐藏]fireAListenerEvent1
和fireBListenerEvent1
方法也存在类似问题我使用的是Java 1.5版。我看不出为什么
BListener
应该扩展AListener
你真的想强迫所有对B
事件感兴趣的人也实现event1()
此外,您不能添加addalitener()
,因为派生类不能降低父类中存在的方法的可见性。此外,您不需要这样做,否则您将违反(每个B必须能够做A可以做的一切)
最后一句话,我要保护
fire*()
方法。通常根本没有理由让它们公开,减少公开成员的数量可以保持你的公开界面干净。我从你对saua的评论中了解到,解雇B会自动解雇A
为什么不使用单一类型的侦听器,然后混合一些继承、委托和泛型呢
class AEvent {}
class BEvent extends Event{}
interface EventListner<E extends AEvent>
{
onEvent(E e);
}
class ListenerManager<E extends AEvent>{
addListner(EventListener<? extends E>){}
removeListner(EventListener<? extends E>){}
fire(E e);
}
class A extends ListenerManager<AEvent>
{
}
class B extends ListenerManager<BEvent>
{
A delegatorA;
@Override addListener(EventListener<? extends BEvent> l)
{
super.addListner(l);
delegatorA.addListener(l);
}
@Override removeListener(EventListener<? extends BEvent> l)
{
super.removeListner(l);
delegatorA.removeListener(l);
}
@Override fire(BEvent b)
{
super.fire(b);
a.fire(b)
}
}
类AEvent{}
类BEvent扩展事件{}
接口事件列表器
{
一个事件(E);
}
类侦听器管理器{
addListner(EventListenerIf
你不能做一些事情,比如:
public class B extends A {
@Override
public synchronized void addAListener(AListener l) {
if (l instanceof BListener) {
...
} else {
super.addAListener(l);
}
}
...
}
正如我在评论中所说的,我不确定你到底想要实现什么?谁从哪里被呼叫,当它被呼叫时需要做什么?在我看来,你可以让事情变得非常简单 我的理解
- 您有一个执行一些基本运算的基本类a
- 您可能有一个更具体的子类B,它还可以执行一些更具体的操作
if( whichEvent instanceof SpecificEvent ) {
SpecificEvent s = ( SpecificEvent ) whichEvent;
// Do something specific here...
}
就这样
你对问题的描述过于抽象,因此可能无法提出具体的解决方案。然而,如果很难解释你想要实现什么,那么你可能首先需要重新分析问题所在
如果我以上的理解是正确的(有时需要处理基本+特定),下面的冗长代码可能会有所帮助
致意
更进一步说,你甚至可以去掉接口以使它更简单基于我们对
A
和B
之间的关系所知甚少,我认为将BListener
作为AListener
的子接口是令人困惑的。顾名思义,BListener
侦听BEvent
s,它已经是AEvent
s的子类。为清楚起见,侦听器应该具有识别目的;它们不应该不必要地重叠。此外,不需要这种重叠侦听器,因为您已经在类B
中定义了单独的方法来处理不同类型的侦听器
为了说明我的观点,请考虑这个例子,在代码之后的样式:
public class MovableMouseEvent extends EventObject
public class ClickableMouseEvent extends MovableMouseEvent
public interface MovableMouseListener extends EventListener
// mouseMoved(MovableMouseEvent)
public interface ClickableMouseListener extends MovableMouseListener
// mouseClicked(ClickableMouseEvent)
public class MovableMouseWidget
// {addMovableMouseListener,removeMovableMouseListener}(MovableMouseListener)
// fireMovableMouseEvent(MovableMouseEvent)
public class ClickableMouseWidget extends MovableMouseWidget
// {addClickableMouseListener,removeClickableMouseListener}(ClickableMouseListener)
// fireClickableMouseEvent(ClickableMouseEvent)
<>这个设计工作,但是混淆了,因为<代码> ClickableMouseListener <代码>处理两种事件,并且public class MouseMoveEvent extends EventObject // note the name change
public class MouseClickEvent extends EventObject // don't extend MouseMoveEvent
public interface MouseMoveListener extends EventListener
// mouseMoved(MouseMoveEvent)
public interface MouseClickListener extends EventListener // don't extend MouseMoveListener
// mouseClicked(MouseClickEvent)
public interface MouseMoveObserver
// {addMouseMoveListener,removeMouseMoveListener}(MouseMoveListener)
// fireMouseMoveEvent(MouseMoveEvent)
public interface MouseClickObserver
// {addMouseClickListener,removeMouseClickListener}(MouseClickListener)
// fireMouseClickEvent(MouseClickEvent)
public class MovableMouseWidget implements MouseMoveObserver
public class ClickableMouseWidget implements MouseMoveObserver, MouseClickObserver
不要使用继承,它不是您想要的,并且会导致脆弱和难以更改的设计。组合是一种更灵活、更好的设计方法。始终尝试设计尽可能精细的接口,因为它们不应在事件中更改。它们是您与系统其余部分的契约。如果新功能要添加的EED第一个选项是向事件添加更多信息。如果这不合适,那么您应该设计一个新的接口来交付该事件。这可以避免更改任何不受影响的现有代码 这是我最喜欢的模式,我相信它通常被称为观察者 创建一个新接口,定义该事件类型的方法(fooEvent()addFooEventListener()removeFooEventListener())。在生成这些事件的具体类中实现该接口。(我通常称之为SourcesFoEvent、FiresFoEvent、FooEventSource等) 如果希望减少代码重复,可以构造一个帮助器类,该类处理侦听器的注册,将它们存储在集合中,并提供发布事件的fire方法 泛型可以在这里提供帮助。首先,泛型侦听器接口:
public interface Listener<T> {
void event(T event);
}
public interface EventSource<T> {
void addListener(Listener<T> listener);
}
公共接口侦听器{
无效事件(T事件);
}
接下来,匹配的EventSource接口:
public interface Listener<T> {
void event(T event);
}
public interface EventSource<T> {
void addListener(Listener<T> listener);
}
公共接口事件源{
void addListener(Listener-Listener);
}
最后是一个抽象的基类来快速地协同工作
public interface EventSource<T> {
void addListener(Listener<T> listener);
}
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);
}
}
}
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);
}
}