文档章节

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

FansUnion
 FansUnion
发布于 2015/10/22 10:30
字数 1266
阅读 3
收藏 0
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);
 }

 }

图片

版权声明:本文为博主原创文章,未经博主允许不得转载。

© 著作权归作者所有

共有 人打赏支持
FansUnion
粉丝 57
博文 858
码字总数 825464
作品 0
丰台
高级程序员
私信 提问

暂无文章

js垃圾回收机制和引起内存泄漏的操作

JS的垃圾回收机制了解吗? Js具有自动垃圾回收机制。垃圾收集器会按照固定的时间间隔周期性的执行。 JS中最常见的垃圾回收方式是标记清除。 工作原理:是当变量进入环境时,将这个变量标记为“...

Jack088
昨天
10
0
大数据教程(10.1)倒排索引建立

前面博主介绍了sql中join功能的大数据实现,本节将继续为小伙伴们分享倒排索引的建立。 一、需求 在很多项目中,我们需要对我们的文档建立索引(如:论坛帖子);我们需要记录某个词在各个文...

em_aaron
昨天
13
0
"errcode": 41001, "errmsg": "access_token missing hint: [w.ILza05728877!]"

Postman获取微信小程序码的时候报错, errcode: 41001, errmsg: access_token missing hint 查看小程序开发api指南,原来access_token是直接当作parameter的(写在url之后),scene参数一定要...

两广总督bogang
昨天
18
0
MYSQL索引

索引的作用 索引类似书籍目录,查找数据,先查找目录,定位页码 性能影响 索引能大大减少查询数据时需要扫描的数据量,提高查询速度, 避免排序和使用临时表 将随机I/O变顺序I/O 降低写速度,占用磁...

关元
昨天
11
0
撬动世界的支点——《引爆点》读书笔记2900字优秀范文

撬动世界的支点——《引爆点》读书笔记2900字优秀范文: 作者:挽弓如月。因为加入火种协会的读书活动,最近我连续阅读了两本论述流行的大作,格拉德威尔的《引爆点》和乔纳伯杰的《疯传》。...

原创小博客
昨天
30
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部