由于JDK中为了方便开发人员,已经写好了现成的观察者接口和被观察者类。

先来观察者接口:

//观察者接口,每一个观察者都必须实现这个接口
public interface Observer {
//这个方法是观察者在观察对象产生变化时所做的响应动作,从中传入了观察的对象和一个预留参数
void update(Observable o, Object arg); }

下面是被观察者类:

import java.util.Vector;

//被观察者类
public class Observable {
//这是一个改变标识,来标记该被观察者有没有改变
private boolean changed = false;
//持有一个观察者列表
private Vector obs; 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);
}
//notifyObservers(Object arg)的重载方法
public void notifyObservers() {
notifyObservers(null);
}
//通知所有观察者,被观察者改变了,你可以执行你的update方法了。
public void notifyObservers(Object arg) {
//一个临时的数组,用于并发访问被观察者时,留住观察者列表的当前状态,这种处理方式其实也算是一种设计模式,即备忘录模式。
Object[] arrLocal;
//注意这个同步块,它表示在获取观察者列表时,该对象是被锁定的
//也就是说,在我获取到观察者列表之前,不允许其他线程改变观察者列表
synchronized (this) {
//如果没变化直接返回
if (!changed)
return;
//这里将当前的观察者列表放入临时数组
arrLocal = obs.toArray();
//将改变标识重新置回未改变
clearChanged();
}
//注意这个for循环没有在同步块,此时已经释放了被观察者的锁,其他线程可以改变观察者列表
//但是这并不影响我们当前进行的操作,因为我们已经将观察者列表复制到临时数组
//在通知时我们只通知数组中的观察者,当前删除和添加观察者,都不会影响我们通知的对象
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();
}
}

观察者模式JDK源码解析的更多相关文章

  1. 设计模式-简单工厂Coding+jdk源码解析

    感谢慕课geely老师的设计模式课程,本套设计模式的所有内容均以课程为参考. 前面的软件设计七大原则,目前只有理论这块,因为最近参与项目重构,暂时没有时间把Coding的代码按照设计思路一点点写出来. ...

  2. Integer.parseInt不同jdk源码解析

    执行以下代码: System.out.println(Integer.parseInt("-123")); System.out.println(Integer.parseInt( ...

  3. JDK源码解析之Java SPI机制

    1. spi 是什么 SPI全称Service Provider Interface,是Java提供的一套用来被第三方实现或者扩展的API,它可以用来启用框架扩展和替换组件. 系统设计的各个抽象,往往 ...

  4. JDK源码解析(一)ArrayList源码解析

    这里为了方便写注释,我是把ArrayList的源码复制下来放到自己创建的类里面的 这个变量则指向具体存放数据的数组 看下构造函数吧 点进去看下LinkedList是怎么数组化的 很弱智吧,就是创建一个 ...

  5. JDK源码解析---HashMap源码解析

    HashMap简介 HashMap是基于哈希表实现的,每一个元素是一个key-value对,其内部通过单链表解决冲突问题,容量不足(超过了阀值)时,同样会自动增长. HashMap是非线程安全的,只是 ...

  6. java JDK源码解析

    Hashmap 使用java语言进行系统开发时,使用得比较多得数据结构hashmap,它以[key,value],进行数据存储,通过key可以快速找到到对应的value值,但是key,value不能是 ...

  7. JDK源码解析string之二

    (28) public boolean startsWith(String prefix, int toffset) { char ta[] = value; int to = toffset; ch ...

  8. 结合JDK源码看设计模式——原型模式

    定义: 指原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象.不需要知道任何创建的细节,不调用构造函数适用场景: 类初始化的时候消耗较多资源 new产生的对象需要非常繁琐的过程 构造函数比较 ...

  9. 【jdk源码分析】ArrayList的size()==0和isEmpty()

    先看结果 分析源码 [jdk源码解析]jdk8的ArrayList初始化长度为0 java的基本数据类型默认值 无参构造 size()方法 isEmpty()方法

随机推荐

  1. matplotlib系列——折线图

    import numpy as np import matplotlib.pyplot as plt import matplotlib #数据准备 #numpy.linspace(start, st ...

  2. 在tkinter中使用matplotlib

    import sys import tkinter as Tk import matplotlib from numpy import arange, sin, pi from matplotlib. ...

  3. unity3D中的Input按键方法检测

    一,按键的按下抬起等识别方法 void Update () { ; ; if (Input.GetKeyDown (KeyCode.A)) { Debug.Log("A按下一次") ...

  4. 彩彩只能变身队团队项目进展记录by后端

    2018.06.03 早上8:00-晚上8:00 后端小组一起在图书馆四楼边学边做: 1.首先搞定了数据库,学会了怎样用命令行来操作数据库,并且建立了一个用户表. 2.然后自己设计了一个简陋的前端页面 ...

  5. 【最新】 ELK之 logstash 同步数据库数据到Elasticsearch

    cd /usr/local 下载logstash 6.4.3版本 wget https://artifacts.elastic.co/downloads/logstash/logstash-6.4.3 ...

  6. for循环(foreach型)语法

  7. SQL查询连续年份

    有这样一个问题,给出一个表格记录了夺冠球队的名称和年份,我们要做的就是写出一条SQL语句,查询再次期间连续夺冠的有哪些,起止时间是什么 下边是代码 create table #t(TEAM vaarc ...

  8. 交叉编译fw_printenv

    source /opt/poky/environment... 创建交叉编译环境. 更改u-boot/tools/env/Make 添加CC 9 CC=aarch64-poky-linux-gcc - ...

  9. nodejs包高效升级插件npm-check-updates

    一.安装 npm install -g npm-check-updates 或 cnpm install -g npm-check-updates 二.使用 ncu crypto ^0.0.3 → ^ ...

  10. 简单递归____Fibonacci数列

    #include <stdio.h> int fun(int x) { ||x==) ; else return fun(x-1)+fun(x-2); } int main() { int ...