本文主要讲解OpenJDK观察者模式的2个工具类,java.util.Observer观察者接口,java.util.Observable被观察者基类。

然后,给出了一个常见的观察者应用示例。

Observer观察者接口

/**
* 一个类可以实现Observer接口,当它想要得到“被观察者”对象变化通知的时候 */
public interface Observer {
/**
* 当被观察的对象发生变化时,这个方法被调用。一个应用调用Observable对象的notifyObservers方法,去通知所有的观察者, Observable对象发生了变化。 * @param o 被观察的对象.
* @param arg 传递给notifyObservers方法的参数.
*/
void update(Observable o, Object arg);
}

Observable被观察者基类

这个类代表一个可以观察的对象,或数据(在模型-视图范式中)。
它能够被继承去代表一个应用想要观察的对象。

一个observable对象可以有一个或多个观察者。
一个观察者可以是一个实现了Observer接口的对象。

当一个observable实例发生了变化,一个应用可以调用Observable的notifyObservers方法,去通知
它的观察者所发生的变化,通过调用观察者的update方法。

通知被传递的顺序是没有指定的。
在Observable类中的默认实现是,按注册顺序通知Observers。
但是子类可以改变这种顺序,使用没有保证的顺序,在分开的线程中传递通知,或者确保他们的子类遵循他们所选择的这个顺序。

注意:这个通知机制和线程没有任何关系,与Object对象的wait和notify机制没有任何关系。

当一个observable被新创建的时候,它的observer集合是空的。
两个observer被认为是同一个,当且仅当他们的equals方法比较返回true的时候。

public class Observable {

    //该对象是否已经发生了变化,默认为false
private boolean changed = false; //Vector是线程安全的,ArrayList是非线程安全的
private Vector obs; //构造一个没有观察者的Observable对象 public Observable() {
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(Object arg) {
//一个临时的数组缓冲,用来作为当前观察者状态的快照
Object[] arrLocal; synchronized (this) {
//我们不想要Observer 回调任何代码,在保持它的Monitor的时候。 //从Vector中提取Observable 和存储Observer的状态的代码需要同步,但是通知观察者却不需要。 //最坏的潜在竞争性条件结果是: //1.一个新增加的观察者将会错误正在进行的通知 //2.一个最近被取消注册的观察者将会被错误的通知,当它不需要关心的时候
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();
} //表明Observable对象已经发生了变化 protected synchronized void setChanged() {
changed = true;
} //表明这个对象已经不再变化,或者说明已经通知到所有的观察者最近的一次变化。
protected synchronized void clearChanged() {
changed = false;
} //测试该对象是否已经发生了变化。当且仅当setChanged方法比clearChanged方法调用的次数更多的时候,返回true。 public synchronized boolean hasChanged() {
return changed;
} // 返回Observable对象的观察者的数量.
public synchronized int countObservers() {
return obs.size();
} }

代码示例

书,被观察者(或者称之为订阅主题)

import java.util.Observable;

//书,被观察者(或者称之为订阅主题)
public class Book extends Observable { // 书的ID
private Integer id;
// 书名
private String name;
// 当前价格
private Double price; // 当书的价格修改时,调用该方法
public void modifyPrice(Double newPrice) {
ChangeStatus status = null;
// 差值大于0.01,就认为价格放生了变化
if (Math.abs(newPrice - price) >= 0.01) {
setChanged();
status = new ChangeStatus();
status.setId(id);
status.setName(name);
status.setOldPrice(price);
status.setNewPrice(newPrice); }
// 通知客户书已经降价
notifyObservers(status); } 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;
} public Integer getId() {
return id;
} public void setId(Integer id) {
this.id = id;
} }

观察者:用户的邮箱

import java.util.Observable;
import java.util.Observer; /**
* 观察者:用户的邮箱
*/
public class BuyerEmail implements Observer { // 该方法会被“被观察者的父类”即Observable调用
public void update(Observable o, Object arg) {
// 这里做具体的发电子邮件的程序
if (arg instanceof ChangeStatus) {
NotifyUtils.sendEmail((ChangeStatus) arg);
}
}
}

观察者:用户的手机

import java.util.Observable;
import java.util.Observer;
/**
* 观察者:用户的手机
*/
public class BuyerMobile implements Observer { // 该方法会被“被观察者的父类”即Observable调用
public void update(Observable o, Object arg) {
// 这里做具体的发电子邮件的程序
if(arg instanceof ChangeStatus){
NotifyUtils.sendSMS((ChangeStatus)arg);
}
} }

一本书的信息变化的实体类

public class ChangeStatus {
//书的ID
private Integer id;
//书名
private String name;
//过去的价格
private Double oldPrice;
//最新的价格
private Double newPrice; public Integer getId() {
return id;
} public void setId(Integer id) {
this.id = id;
} public Double getOldPrice() {
return oldPrice;
} public void setOldPrice(Double oldPrice) {
this.oldPrice = oldPrice;
} public Double getNewPrice() {
return newPrice;
} public void setNewPrice(Double newPrice) {
this.newPrice = newPrice;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} }

发送通知的工具类

public class NotifyUtils {
// 发送邮件通知用户
public static void sendEmail(ChangeStatus status) {
print(status);
} // 发送短信通知用户
public static void sendSMS(ChangeStatus status) {
print(status);
} // 一种只是用来作为“演示”的发送信息的方法
private static void print(ChangeStatus status) {
println("*******************************************************");
String messageContent = messageContent(status);
println(messageContent);
println("********************************************************");
} private static String messageContent(ChangeStatus status) {
// 一般,降价才会通知,这里只当是降价了
String str = "尊敬的用户,您好!\n";
str += "您收藏的图书《" + status.getName() + "》降价了。\n";
str += "过去的价格是:" + status.getOldPrice() + "\n";
str += "现在的价格是:" + status.getNewPrice() + "\n";
str += "您可以通过以下链接 http://blog.csdn.net/FansUnion 进行购买。";
return str;
} private static void println(Object content) {
System.out.println(content);
}
}

程序入口

public class ObserverPatternTest {

    /**
* 观察者模式-用法示例
*/
public static void main(String[] args) {
Book book = new Book();
book.setName("中国象棋程序的设计与实现");
book.setPrice(45.0); // 下面的观察者在实际应用中可以从数据库或文件中读取
BuyerEmail email = new BuyerEmail();
BuyerMobile mobile = new BuyerMobile(); // 增加观察者,在实际应用中就是哪些人对该书作了关注
book.addObserver(email);
book.addObserver(mobile); book.modifyPrice(34.00); }
}

输出结果

*******************************************************
尊敬的用户,您好!
您收藏的图书《中国象棋程序的设计与实现》降价了。
过去的价格是:45.0
现在的价格是:34.0
您可以通过以下链接 http://blog.csdn.net/FansUnion 进行购买。
********************************************************
*******************************************************
尊敬的用户,您好!
您收藏的图书《中国象棋程序的设计与实现》降价了。
过去的价格是:45.0
现在的价格是:34.0
您可以通过以下链接 http://blog.csdn.net/FansUnion 进行购买。
********************************************************

参考资料:OpenJDK7源码

原文参见: http://FansUnion.cn/articles/2936

最新文章

  1. Xamarin.Android活动的生命周期
  2. 关于click和submit的笔记
  3. [Oracle]快速插入大量(100w)数据
  4. SYN Flood应如何应对
  5. iOS - 富文本AttributedString
  6. DS实验题 Dijkstra算法
  7. Oracle练习题20~33
  8. samba配置只读共享
  9. ubuntu下使用apt-get install安装的软件在哪个目录
  10. Delphi与Qt在Windows下使用共享内存进程间通信
  11. 阿里云ECS每天一件事D2:配置防火墙
  12. Apriori算法-数组-C语言
  13. C#实体类生成XML与XML Schema文档
  14. 导入网页数据到 Google Sheet
  15. TFboy养成记 多层感知器 MLP
  16. HDU 1874 畅通工程续(模板题——Floyd算法)
  17. Py中map与np.rival学习
  18. 从requests源码分析中学习python(一)
  19. [NL系列] RNN & LSTM 网络结构及应用
  20. VS编译器之间相互打开的技巧

热门文章

  1. jqGrid收藏的链接
  2. 【原创】java中各种集合类的实现浅析
  3. 《剑指offer》数组中出现次数超过一半的数字
  4. 1、Windows服务器 VS Linux服务器
  5. 给DOM操作生成的元素添加事件
  6. [SHOI2009]Booking 会场预约
  7. 安装anaconda和tensorflow
  8. The Zen of Python, by Tim Peters
  9. 【BZOJ 1193】 [HNOI2006]马步距离
  10. SpringBoot之通过Maven将项目打包成ROOT.war-yellowcong