事件响应机制与观察者模式

来源:互联网 发布:沃伦夫妇纪录片 知乎 编辑:程序博客网 时间:2024/05/23 20:30
GUI事件处理和程序中使用接口回调

   这种一次性注册回调程序的方式允许由运行时系统在需要回调某个事件处理程序时做出初步的决定,而不是由处理程序决定。

 

下面通过代码分步骤详细解释这一过程:

1.      运行时库定义了一个接口,其中承诺有一个itHappened()方法。

示例如下:

Public interfaceActionListener{

 Public void itHappened();

}

运行时系统将会调用接口承诺的上述方法。

 

2.      处理程序代码将实现这一接口。

    因此,我们将在自己的程序代码中提供了一个实现了上述接口的类:

ClassMyActionListener implements ActionListener{

Public voidinHappened(){

//…

}

}

这就是我们的一个事件处理程序。

 

3.      在我们的应用程序代码中,一次性地调用运行时库,注册自己感兴趣的点击按钮等事件,并告之事件处理程序。

MyActionListenerlistener = new MyActionListener();

Runtime.registerActionListener(listener);

 

4.      在运行时系统中,注册例程将保存对任何注册对象的引用。

PrivateActionListener[] registeredObjects;

registerActionListener(ActionListenerlistener){

  registerObjects[i] = listener;

}

 

5.      这一步时前面所有步骤的最终目的。

   无论何时运行时系统检查发现一个GUI事件出现,它将回调任何已经注册为处理相应事件的itHappened()方法:

For(ActionListenerlistener:registerObjects){

  Listener.itHappened();

}

当事件发生时,可能需要通知一系列已经注册到运行时系统的ActionListener,但经常只有一个时正确的。

这就是GUI事件处理程序的工作原理。其中关键的一点是第5步的代码需要在一个单独的线程中运行,使之能够在任何时刻反向调用ActionListener,因而称为回调(CallBack)。

 

 

事件响应机制实际上就使用了观察者模式,以下是一个观察者模式的具体例子。

 

public abstract class Subject {

 private boolean changed = false;
 private Vector obs;

 

 public Subject() {
  obs = new Vector();
 }

 

 public synchronized void addObserver(Observer o) {
  if (o == null)
   throw new NullPointerException();
  if (!obs.contains(o)) {
   obs.addElement(o);
  }
 }

  public synchronized void deleteObserver(Observer o) {
  obs.removeElement(o);
 }

  public void notifyObservers() {
  notifyObservers(null);
 }

  public void notifyObservers(Subject arg) {

  Object[] arrLocal;

  synchronized (this) {

   if (!changed)
    return;
   arrLocal = obs.toArray();
   clearChanged();
  }

  for (int i = arrLocal.length - 1; i >= 0; i--)
   ((Observer) arrLocal[i]).update(this, arg);
 }

 public synchronized void deleteObservers() {
  obs.removeAllElements();
 }

 protected synchronized void setChanged() {
  changed = true;
 }

 protected synchronized void clearChanged() {
  changed = false;
 }

 public synchronized boolean hasChanged() {
  return changed;
 }

 public synchronized int countObservers() {
  return obs.size();
 }
}

 

package org.leiwen.dp.action.observer;

public class Book extends Subject {

 private String name;

 private double price;

 // 更新书籍信息,调用该方法
 public void update(Book book) {
  if (book == null) {
   return;
  }

  boolean isSame = name.equals(book.getName())
    && (price == book.getPrice());
  if (!isSame) {
   setChanged();
  }
  // 通知客户书已经更新
  notifyObservers(book);

 }

 public String getName() {
  return name;
 }

 public void setName(String name) {
  this.name = name;
 }

 public double getPrice() {
  return price;
 }

 public void setPrice(double price) {
  this.price = price;
 }

}

 

package org.leiwen.dp.action.observer;

public class Mouse extends Subject {
 private String name;

 private double price;

 // 更新鼠标信息,调用该方法
 public void update(Mouse mouse) {
  if (mouse == null) {
   return;
  }

  boolean isSame = name.equals(mouse.getName())
    && (price == mouse.getPrice());
  if (!isSame) {
   setChanged();
  }
  // 通知客户鼠标已经更新
  notifyObservers(mouse);

 }

 public String getName() {
  return name;
 }

 public void setName(String name) {
  this.name = name;
 }

 public double getPrice() {
  return price;
 }

 public void setPrice(double price) {
  this.price = price;
 }

}

 

 package org.leiwen.dp.action.observer;

public interface Observer {

 // 参数个数和类型可以自定义
 void update(Subject o, Subject arg);
}

 

package org.leiwen.dp.action.observer;

//观察者
public class BuyerEmail implements Observer {

 // 该方法会被“被观察者的父类”即Observable调用
 @Override
 public void update(Subject subject, Subject arg) {
  //更新算法多种多样,根据实际情况而定
  // 这里是具体的发电子邮件的程序
  System.out.println("邮件收到的消息:"
    + ObserverUtil.getNotifyMessage(subject, arg));
 }

}

 

package org.leiwen.dp.action.observer;

//观察者
public class BuyerMobile implements Observer {

 // 该方法会被“被观察者的父类”即Subject调用
 @Override
 public void update(Subject subject, Subject arg) {
  // 这里是具体的发手机短信的程序
  System.out.println("手机收到的消息:"
    + ObserverUtil.getNotifyMessage(subject, arg));

 }
}

 

package org.leiwen.dp.action.observer;

public abstract class ObserverUtil {

 // 工具类,根据书原有的信息和新的信息,构造向用户发送的消息内容。
 public static String getNotifyMessage(Subject subject, Subject arg) {
  // 具体构造算法,需要根据实际情况而定
  String message = "";

  if (subject instanceof Book && arg instanceof Book) {

   Book oldBook = (Book) subject;
   Book newBook = (Book) arg;

   double diff = newBook.getPrice() - oldBook.getPrice();
   if (diff < 0) {
    message = "亲爱的Fans,<<" + newBook.getName() + ">>降价"
      + Math.abs(diff) + "元! 快来购买吧!";
   }
  } else if (subject instanceof Mouse && arg instanceof Mouse) {

   Mouse oldMouse = (Mouse) subject;
   Mouse newMouse = (Mouse) arg;

   double diff = newMouse.getPrice() - oldMouse.getPrice();
   if (diff < 0) {
    message = "亲爱的Fans," + newMouse.getName() + "降价"
      + Math.abs(diff) + "元! 快来购买吧!";
   }
  }
  return message;

 }
}

 

package org.leiwen.dp.action.observer;

public class ObserverTest {

 public static void main(String[] args) {
  // ------------------第1个测试例子-----------------------------
  // 主题,被观察者
  Book book = new Book();
  book.setName("Struts2技术内幕");
  book.setPrice(45.3);

  // 下面的观察者在实际应用中可以从数据库或文件中读取
  BuyerEmail be = new BuyerEmail();
  BuyerMobile bm = new BuyerMobile();

  // 增加观察者,在实际应用中就是哪些人对该书作了关注
  book.addObserver(be);
  book.addObserver(bm);

  Book updatedBook = new Book();
  updatedBook.setName(book.getName());
  updatedBook.setPrice(book.getPrice() - 3);
  book.update(updatedBook);

  // ------------------第2个测试例子-----------------------------
  // 主题,被观察者
  Mouse mouse = new Mouse();
  mouse.setName("雷柏3100P鼠标");
  mouse.setPrice(55.6);

  // 下面的观察者在实际应用中可以从数据库或文件中读取
  BuyerEmail be2 = new BuyerEmail();
  BuyerMobile bm2 = new BuyerMobile();

  // 增加观察者,在实际应用中就是哪些人对该鼠标作了关注
  mouse.addObserver(be2);
  mouse.addObserver(bm2);

  Mouse updatedMouse = new Mouse();
  updatedMouse.setName(mouse.getName());
  updatedMouse.setPrice(mouse.getPrice() - 5);
  mouse.update(updatedMouse);
 }

 }

图片

原创粉丝点击