当前位置:  开发笔记 > 编程语言 > 正文

Java Listener继承

如何解决《JavaListener继承》经验,为你挑选了2个好方法。

我有一个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类都有addAListeneraddBListener方法.我应该使用私有关键字隐藏addAListener吗?[更新:无法隐藏私人关键字]

    类似的问题fireAListenerEvent1fireBListenerEvent1方法.

我正在使用Java 1.5版.



1> Joachim Saue..:

我没有看到为什么BListener要扩展的原因AListener.

你真的想强迫每个对B事件感兴趣的人也实施event1()吗?

此外,您无法添加addAListener(),因为派生类无法降低父类中存在的方法的可见性.此外,你不应该,或者你会违反Liskov替换原则(每个B必须能够完成A能做的所有事情).

作为最后一句话,我会使fire*()方法受到保护.通常没有理由让它们公开,减少公共成员的数量可以保持公共界面的清洁.



2> Mark Renouf..:

不要使用继承,它不是你想要的,会导致脆弱和难以改变的设计.组合是一种更灵活,更好的设计方法.始终尝试尽可能精细地设计接口,因为它们不应该被更改为事件.它们是您与系统其余部分的合同.如果需要添加新功能,则第一个选项是向事件添加更多信息.如果这不合适,那么您应该设计一个新的界面来提供该事件.这可以防止必须更改任何不受影响的现有代码.

这是我最喜欢的模式,我相信它通常被称为观察者.

创建一个新的接口,用于定义该事件类型的方法(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);
  }
}

希望这说明了类型安全(重要),灵活性和代码重用之间的良好平衡.

推荐阅读
和谐啄木鸟
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有