Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/321.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java侦听器继承_Java_Inheritance_Events_Listener - Fatal编程技术网

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) { ..

我有一个触发自定义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
    方法。我应该用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,它还可以执行一些更具体的操作

    如果是这种情况,您需要同时处理这两个事件(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 <代码>处理两种事件,并且 CLIKABMLUWEXWIDGET 处理两种侦听器,正如您正确指出的。现在,考虑下面的替代方案,即使用构图而不是继承:

    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);
      }
    }