认识观察者模式

首先来看看报纸订阅的过程

  • 1.报社的业务就是出版报纸
  • 2.向某家报社订阅报纸,只要他们有新报纸出版,就会送过来,只要你是他们的订户
  • 3.当你不想再看报纸的时候,取消订阅,他们就不会再送新报纸
  • 4.只要报社还在运营,就会一直有人来订阅或取消订阅报纸

观察者模式和报纸订阅流程是一样的,只是名字不同。出版社改名为主题(Subject),而订阅者改名为观察者(Observer)

观察者模式的定义

观察者模式定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会受到通知并自动更新。

观察者模式代码

//主题接口
interface Subject {
    void registerObserver(Observer o);//增加观察者
    void removeObserver(Observer o);//删除观察者
    void notifyObservers();//当主题状态改变时,调用此方法通知所有观察者
}
//观察者接口
interface Observer {
    void update(float temp); //用来接收主题发送的通知,这里假设主题是温度计,通过接口给观察者发送当前温度
}
//主题实现
class Thermometer implements Subject {
    private List<Observer> observers = new ArrayList<>();//观察者集合
    private float temp = 0.0f;//温度
    public void setTemp(float temp) {//温度更新
        this.temp = temp;
        notifyObservers();
    }
    @Override
    public void registerObserver(Observer o) {
        observers.add(o);
    }
    @Override
    public void removeObserver(Observer o) {
        if (observers.indexOf(o) >= 0)
            observers.remove(o);
    }
    @Override
    public void notifyObservers() {
        for (Observer observer : observers) {
            observer.update(temp);
        }
    }
}
//观察者实现
class ObserverA implements Observer {
    @Override
    public void update(float temp) {
        System.out.println("观察者A:当前的温度是" + temp);
    }
}
class ObserverB implements Observer {
    @Override
    public void update(float temp) {
        System.out.println("观察者B:当前的温度是" + temp);
    }
}
public class JavaApplication {
    public static void main(String[] args) throws Exception{
       //具体使用
       Thermometer t = new Thermometer();
       Observer a = new ObserverA();
       Observer b = new ObserverB();
       //为a,b注册成为ts的观察者
       t.registerObserver(a);
       t.registerObserver(b);
       //更新温度
       t.setTemp(23.00f);
       //a不再当观察者
       t.removeObserver(a);
       //更新温度
       t.setTemp(24.00f);
    }
}

另外,Java中已经内置了观察者模式,在java.util包下有Observer接口和Observable类

和这里的Subject接口和Observer接口很相似,修改后的代码如下

//主题实现
class Thermometer extends Observable{
    private float temp = 0.0f;//温度
    public void setTemp(float temp) {//温度更新
        this.temp = temp;
        setChanged();//说明状态已改变
        notifyObservers(temp);
    }
}
//观察者实现
class ObserverA implements Observer {
    @Override
    public void update(Observable o, Object arg) {
        System.out.println("观察者A:当前的温度是" + arg);
    }
}
class ObserverB implements Observer {
    @Override
    public void update(Observable o, Object arg) {
        System.out.println("观察者B:当前的温度是" + arg);
    }
}
public class JavaApplication {
    public static void main(String[] args) throws Exception{
       //具体使用
       Thermometer t = new Thermometer();
       Observer a = new ObserverA();
       Observer b = new ObserverB();
       //为a,b注册成为ts的观察者
       t.addObserver(a);
       t.addObserver(b);
       //更新温度
       t.setTemp(23.00f);
       //a不再当观察者
       t.deleteObserver(a);
       //更新温度
       t.setTemp(24.00f);
    }
}

另外,既然JDK是开源的,那么就顺便去看看JDK的源码中的具体实现

(这里使用的源码版本为jdk1.8.0_74)

Observable对象:(大部分没什么区别的代码就不放出来了)

public Class Observable {
    private boolean changed = false;
    private Vector<Observer> obs;

    ...
}

私有成员变量,一个是标志,用于后续判断是否通知观察者,一个观察者集合obs,使用的是Vector容器

标志的用途是用于增加自由度,比如说一秒钟更新10次数据,对于前台显示而言可能不需要这么频繁,那么我们可以自己计数,如果达到10次才设置标志

可以在通知观察者方法源码里看到changed的作用

public void notifyObservers(Object arg) {
    Object[] arrLocal;
    synchronized (this) {
        if (!changed)
            return;
        arrLocal = obs.toArray();
        clearChanged();//clearChanged方法里的具体代码就一句:changed = false;
    }
    for (int i = arrLocal.length-1; i>=0; i--)
        ((Observer)arrLocal[i]).update(this, arg);
}

而Observer接口更是没什么好说的

public interface Observer {
    void update(Observable o, Object arg);
}

相对于我们自己实现的观察者模式,主要区别在于将ArrayList换成了Vector,方法都加上了synchronized关键字来保证线程安全,并没有什么特别的← ←

Head First Design Patterns学习笔记-观察者模式的更多相关文章

  1. how to design Programs 学习笔记

    how to design Programs 学习笔记 */--> how to design Programs 学习笔记 目录 1. 前言 1.1. 系统化程序设计 1.2. 输入和输出 2. ...

  2. 《Head First 设计模式》学习笔记——观察者模式 + 装饰者模式

    装饰者模式是JDK中还有一个使用较多的设计模式,上一个是观察者模式(在Swing中大量使用),业内好的API设计无一离不开常见的设计模式,通常我们所说要阅读源代码,也是为了学习大牛们的设计思路.--- ...

  3. 学习笔记——观察者模式Observer

    观察者模式,当事件发生时,调用相应观察者的方法进行“通知”.Subject中使用一个数据结构存储需要通知的观察者对象,执行Notify时,执行所有观察者的Update方法.

  4. C#学习笔记-观察者模式

    题目1:几个同事为了在上班期间偷偷看休息,做点其他的事情,就和小秘偷偷联系了一下,如果老板回来了,就麻烦小秘偷偷通知一声,这样方便大家及时变更自己的工作状态. 分析: 根据题目分析,首先明确,肯定会有 ...

  5. Java 学习笔记 观察者模式与适配者模式 监控文件夹

    2019.4.12 适配器模式,如果某个类需要实现多个方法,但是开发过程中只需要实现其中的一两个方法,直接使用该类的适配器类,复写需要实现的方法即可 观察者模式:有多个观察者observe观察一个主体 ...

  6. Fusion360_Generative Design 入门学习笔记

    2019.12.17更新 初次见到衍生式设计的时候感觉非常惊艳,现在觉得这个功能就是个弟弟,只能做一些中看不中用的东西.这个方法的理论基础是拓扑优化,想做research的同学可参阅"如何入 ...

  7. Ant Design Pro 学习笔记:数据流向

    在讲这个问题之前,有一个问题应当讲一下: Ant Design Pro / umi / dva 是什么关系? 首先是 umi / dva 的关系. umi 是一个基于路由的 react 开发框架. d ...

  8. Java-马士兵设计模式学习笔记-观察者模式-模拟Awt Button

    一.概述 Java 的Awt是 Observer模式,现用Java自己模拟awt中Button的运行机制 二.代码 1.Test.java import java.text.DateFormat; i ...

  9. Java-马士兵设计模式学习笔记-观察者模式-AWT简单例子

    1.AWT简单例子 TestFrame.java import java.awt.Button; import java.awt.Frame; import java.awt.event.Action ...

随机推荐

  1. idea启动tomcat失败,1099端口被占用

    今天遇到一个问题,当使用idea启动一个tomat服务的时候,报错:不能连接本地1099端口. /Users/liqiu/soft/develop/apache-tomcat-/bin/catalin ...

  2. 数据人员Sql必会列转行

    列转行上一篇博客已经介绍过了. 下面介绍一下行转列的实现 假设我们有一个数据表: CREATE TABLE row_to_line ( ) NOT NULL, -- 学生名称 yingyu integ ...

  3. 在linux下配置静态IP

    在终端中输入:vi /etc/sysconfig/network-scripts/ifcfg-eth0   开始编辑,填写ip地址.子网掩码.网关.DNS等.其中“红框内的信息”是必须得有的.   编 ...

  4. BI项目需求分析书-模板

    目录 目录 .............................................................................................. ...

  5. ORM:ODB安装使用过程

      1.下载odb-2.4.0-i686-windows,是cpp和sql文件生成工具,已经编译好了,如果下odb-2.4.0估计是未编译好的这个项目:   2.将...\odb-2.4.0-i686 ...

  6. 注意啦!10 个你需要了解的 Linux 网络和监控命令

    下面列出来的10个基础的每个Linux用户都应该知道的网络和监控命令.网络和监控命令类似于这些:hostname, ping, ifconfig, iwconfig, netstat, nslooku ...

  7. 【原创】C#搭建足球赛事资料库与预测平台(2) 数据库与XCode组件

            本博客所有文章分类的总目录:[总目录]本博客博文总目录-实时更新 开源C#彩票数据资料库系列文章总目录:[目录]C#搭建足球赛事资料库与预测平台与彩票数据分析目录  本篇文章开始将逐步 ...

  8. php -- php读取sqlserver2005的数据实现分页查询

    --php5.2 --sqlserver2005 php读取sqlserver多条数据时,有时因为数据太多,需要进行分页查询. 例如,按价格的顺序,读取同一类型的产品的第30到第48条记录 $star ...

  9. Hadoop第5周练习—MapReduce计算气象温度等例子

    :对云计算的看法 内容 :使用MapReduce求每年最低温度 内容 :求温度平均值能使用combiner吗? 内容 :使用Hadoop流求最高温度(awk脚本) 内容 :使用Hadoop流求最高温度 ...

  10. C++ 封装互斥对象

    多线程程序中为了防止线程并发造成的竞态,需要经常使用到Mutex进行数据保护.posix提供了phtread_mutex_t进行互斥保护数据.Mutex的使用需要初始化和释放对应(phtread_mu ...