大学IT网 - 最懂大学生的IT学习网站! QQ资料交流群:367606806
当前位置:大学IT网 > Java技巧 > Java中使用观察者模式实现自定义事件

Java中使用观察者模式实现自定义事件


[摘要]本文主要是对Java中使用观察者模式实现自定义事件的讲解,希望对大家学习Java中使用观察者模式实现自定义事件有所帮助。

  MyEventTest.java:

  package wintys.event;

  import javax.swing.event.EventListenerList;

  import java.util.Date;

  import java.text.DateFormat;

  import java.text.SimpleDateFormat;

  /**

  * Java的事件机制/自定义事件.

  运行结果:

  do something interesting in source here.

  listener detects [event]:wintys.event.MyEvent[source=wintys.event.MySource@18158

  59] [occur at]:2009-10-11 16:27:49

  listener detects [event]:wintys.event.MyEvent[source=wintys.event.MySource@18158

  59] [occur at]:2009-10-11 16:27:49

  * @version 2009-10-11

  * @author 天堂露珠 (wintys@gmail.com)

  * @see http://www.blogjava.net/wintys

  */

  class MyEventTest{

  public static void main(String[] args){

  MySource source = new MySource();

  MyListener myListener = new MyListener(){

  public void doMyAction(MyEvent e){

  System.out.println("listener detects " + e);

  }

  };

  source.addMyListener(myListener);

  source.addMyListener(myListener);

  source.addMyListener(myListener);

  source.removeMyListener(myListener);

  source.doSomething();

  }

  }

  /**

  * 自定义的事件.

  * @version 2009-10-11

  * @author 天堂露珠(wintys@gmail.com)

  * @see http://www.blogjava.net/wintys

  */

  class MyEvent extends java.util.EventObject{

  private Date date;//记录事件发生的时间

  public MyEvent(Object source , Date date){

  super(source);

  this.date = date;

  }

  public String toString(){

  DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

  String dt = df.format(date);

  return "[event]:" + super.toString() + " [occur at]:" + dt;

  }

  }

  /**

  * 自定义事件监听器接口.

  * @version 2009-10-11

  * @author 天堂露珠(wintys@gmail.com)

  * @see http://www.blogjava.net/wintys

  */

  interface MyListener extends java.util.EventListener{

  void doMyAction(MyEvent e);

  }

  /**

  * 自定义事件源.

  * @version 2009-10-11

  * @author 天堂露珠(wintys@gmail.com)

  * @see http://www.blogjava.net/wintys

  */

  class MySource{

  /**

  * 保存注册的监听器列表.

  * 子类可以使用它保存自己的事件监听器(非MyListener监听器)列表.

  */

  protected EventListenerList listenerList = new EventListenerList();

  private MyEvent myEvent = null;//fireDoMyAction()使用此变量

  /**

  * 没有做任何事

  */

  public MySource(){

  }

  /**

  * 添加一个MyListener监听器

  */

  public void addMyListener(MyListener listener){

  listenerList.add(MyListener.class , listener);

  }

  /**

  * 移除一个已注册的MyListener监听器.

  * 如果监听器列表中已有相同的监听器listener1、listener2,

  * 并且listener1==listener2,

  * 那么只移除最近注册的一个监听器。

  */

  public void removeMyListener(MyListener listener){

  listenerList.remove(MyListener.class , listener);

  }

  /**

  * @return 在此对象上监听的所有MyListener类型的监听器

  */

  public MyListener[] getMyListeners(){

  return (MyListener[])listenerList.getListeners(MyListener.class);

  }

  //Winty:Copy directly from javax.swing.event.EventListenerList

  /*Notify all listeners that have registered interest for

  notification on this event type. The event instance

  is lazily created using the parameters passed into

  the fire method.

  */

  protected void fireDoMyAction() {

  // getListenerList() Guaranteed to return a non-null array

  Object[] listeners = listenerList.getListenerList();

  // Process the listeners last to first, notifying

  // those that are interested in this event

  for (int i = listeners.length-2; i>=0; i-=2) {

  if (listeners[i]==MyListener.class) {

  // Lazily create the event:

  if (myEvent == null)

  myEvent = new MyEvent(this , new Date());

  ((MyListener)listeners[i+1]).doMyAction(myEvent);

  }

  }

  }

  /**

  * 做一些事件源应该做的有意义的事,然后通知监听器.

  * 这里只是一个示例方法.

  * 例如:MySource如果是一个按钮,则doSomething()就可以命名为click(),

  * 当用户点击按钮时调用click()方法.

  */

  public void doSomething() {

  System.out.println("do something interesting here.");

  fireDoMyAction();//通知监听器

  }

  }

  EventListenerList是特别需要说明的,它内部使用一个Object数组存放监听器。但是它并不是直接存放,而是先存监听器的class类型,然后再存监听器本身。即存放(MyListener.class , myListener)。一个Object数组可以存放多种类型的Listener,如果还有一种监听器AnotherListener,那么(AnotherListener.class , anotherListener)也可以存放。无论增删都是两个对象一同被添加或删除。上述代码中的listenerList.add(MyListener.class , listener)或listenerList.remove(MyListener.class , listener),以及fireDoMyAction()中的"i-=2",就是这样操作的。



相关评论