OpenJDK源码研究笔记(六)--观察者模式工具类(Observer和Observable)和应用示例
本文主要讲解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
OpenJDK源码研究笔记(六)--观察者模式工具类(Observer和Observable)和应用示例的更多相关文章
- OpenJDK源码研究笔记(八)-详细解析如何读取Java字节码文件(.class)
在上一篇OpenJDK源码研究笔记(七)–Java字节码文件(.class)的结构中,我们大致了解了Java字节码文件的结构. 本篇详细地介绍了如何读取.class文件的大部分细节. 1.构造文件 ...
- OpenJDK源码研究笔记(四)-编写和组织可复用的工具类和方法
本篇主要讲解java.util.Arrays这个针对数组的工具类. 1.可复用的工具类和方法. 这个工具类里,包含很多针对数组的工具方法,如 排序.交换.二分查找.比较.填充.复制.hashcode ...
- OpenJDK源码研究笔记(十四):三种经典的设计方法,接口,接口-抽象类-具体实现类,接口-具体实现类
在研究OpenJDK源码过程中,我发现常用的设计方法就是2种:接口,接口-抽象类-具体实现类 . 在一些其它开源框架和业务开发中,经常存在着第3种设计,接口-具体实现类. 1.只有接口,没有实现类. ...
- OpenJDK源码研究笔记(五)-缓存Integer等类型的频繁使用的数据和对象,大幅度提升性能(一道经典的Java笔试题)
摘要 本文先给出一个看似很简单实则有深意的Java笔试面试题,引出JDK内部的缓存. JDK内部的缓存,主要是为了提高Java程序的性能. 你能答对这道"看似简单,实则有深意"的J ...
- OpenJDK源码研究笔记(二)-Comparable和Comparator2个接口的作用和区别(一道经典的Java笔试面试题)
Comparable和Comparator是JDK中定义的2个比较接口,很相似,但又有所不同. 这2个接口的作用和区别也是Java中的常见经典面试题. 下面我们就来详细介绍下这2个接口的定义.作用.区 ...
- OpenJDK源码研究笔记(七)–Java字节码文件(.class)的结构
最近在看OpenJDK源码的过程中,顺便看了Java编译器(javac)的源码. 为了理解javac的源码,需要先搞懂Java字节码文件(.class)的结构. 于是,我就认真看了下OpenJDK中J ...
- OpenJDK源码研究笔记(十):枚举的高级用法,枚举实现接口,竟是别有洞天
在研究OpenJDK,Java编译器javac源码的过程中,发现以下代码. 顿时发现枚举类竟然也有如此"高端大气上档次"的用法. 沙场点兵(用法源码) com.sun.tools. ...
- OpenJDK源码研究笔记(十五):吐槽JDK中的10个富有争议的设计
前14篇文章,分享了JDK中值得学习和借鉴的编码和设计方法. 每个硬币都是有两面的.Every coin has two sides. 当然,JDK中也有很多值得改进或者说富有争议的设计. 本篇,就来 ...
- OpenJDK源码研究笔记(十三):Javac编译过程中的上下文容器(Context)、单例(Singleton)和延迟创建(LazyCreation)3种模式
在阅读Javac源码的过程中,发现一个上下文对象Context. 这个对象用来确保一次编译过程中的用到的类都只有一个实例,即实现我们经常提到的"单例模式". 今天,特意对这个上下文 ...
随机推荐
- python 3.x 学习笔记13 (网络编程socket)
1.协议http.smtp.dns.ftp.ssh.snmp.icmp.dhcp....等具体自查 2.OSI七层应用.表示.会话.传输.网络.数据链路.物理 3.socket: 对所有上层协议的封装 ...
- 对比学习用 Keras 搭建 CNN RNN 等常用神经网络
Keras 是一个兼容 Theano 和 Tensorflow 的神经网络高级包, 用他来组件一个神经网络更加快速, 几条语句就搞定了. 而且广泛的兼容性能使 Keras 在 Windows 和 Ma ...
- Scrapy中scrapy.Request和response.follow的区别
在写scrapy的spider类的parse方法的时候,有些链接需要提取出来继续爬取,这里scrapy提供了一些方法可以方便的实现这个功能,总结如下: 假设我们的目标a标签是target_a 方法1: ...
- 让placeholder中的默认文字居中,或者缩进多少像素
直接给input或者textarea的样式加texta-align:center; <input type="" name="" id="&qu ...
- C# HttpHelper万能框架实现 接口
POST请请求是使用Http协议与请求的URL进行连接,然后再写入数据,最后关闭连接的过程 方法(1) //要Post的数据 string postdate = "a=123&c=4 ...
- C# 热敏打印机 小票打印机 打印图片
最近一直在研究并口小票打印机打印图片问题,这也是第一次和硬件打交道,不过还好,最终成功了. 这是DEMO的窗体: 下面是打印所需要调用的代码: 因为我们这里主要是打印条形码和二维码,所以以条形码和二维 ...
- 5、AFM(Attention+FM)-----Attentional Factorization Machines:Learning the Weight of Feature Interactions via Attention Network
1.摘要: 提出一个Attentional FM,Attention模型+因子分解机,其通过Attention学习到特征交叉的权重.因为很显然不是所有的二阶特征交互的重要性都是一样的,如何通过机器自动 ...
- HTTP——学习笔记(3)
HTTP报文:用于HTTP协议交互的信息,客户端的HTTP报文叫做 请求报文,响应端的叫做 响应报文 本质:是由多行(用CR+LF作换行符)数据构成的字符串文本 注:CR:回车,打印针回到行首 L ...
- debug和release的区别
Debug和Release,主要是针对其面向的目标不同的而进行区分的.Debug通常称为调试版本,通过一系列编译选项的配合,编译的结果通常包含调试信息,而且不做任何优化,以为开发人员提供强大的应用程序 ...
- 【Hibernate学习】 ——ORM(二)
上篇博客主要介绍了一对一的关系,主要理解单向与双向的差别,主键关联与唯一外键关联的差别.以下继续介绍一对多与多对多关联. 一对多关联映射 一个班级相应多个学生 watermark/2/text/aHR ...