一、概述

  当对象间存在一对多关系时,则使用观察者模式(Observer Pattern)。比如,当一个对象被修改时,则会自动通知它的依赖对象。

  定义了对象之间的一对多依赖,让多个观察者对象同时监听某一个主题对象,当主题对象发生变化时,它的所有依赖者(观察者)都会收到通知并更新。

  Observer模式提供给关联对象一种同步通信的手段,使某个对象与依赖它的其他对象之间保持状态同步。

1.1、适用场景

  一个对象状态改变给其他对象通知的问题,而且要考虑到易用和低耦合,保证高度的协作。

  关联行为场景,建立一套触发机制

典型应用

    1、侦听事件驱动程序设计中的外部事件

    2、侦听/监视某个对象的状态变化

    3、发布者/订阅者(publisher/subscriber)模型中,当一个外部事件(新的产品,消息的出现等等)被触发时,通知邮件列表中的订阅者

1.2、优缺点

优点:

  • 观察者和被观察者之间建立一个抽象的耦合
  • 观察者模式支持广播通信,建立一套触发机制。

缺点:

  • 观察者之间有过多的细节依赖、提高时间消耗及程序复杂度
  • 使用要得当,要避免循环调用

1.3、类图角色及其职责

  

  1、Subject(被观察者)
      被观察的对象。当需要被观察的状态发生变化时,需要通知队列中所有观察者对象。Subject需要维持(添加,删除,通知)一个观察者对象的队列列表。

  2、ConcreteSubject
      被观察者的具体实现。包含一些基本的属性状态及其他操作。

  3、Observer(观察者)
      接口或抽象类。当Subject的状态发生变化时,Observer对象将通过一个callback函数得到通知。

  4、ConcreteObserver
      观察者的具体实现。得到通知后将完成一些具体的业务逻辑处理。

1.4、演进过程

使用:被观察者想要起作用,就必须继承java.util包下的Observable类

构造方法摘要
Observable() 
          构造一个带有零个观察者的 Observable。
方法摘要
 void addObserver(Observer o) 
          如果观察者与集合中已有的观察者不同,则向对象的观察者集中添加此观察者。
protected  void clearChanged() 
          指示对象不再改变,或者它已对其所有的观察者通知了最近的改变,所以 hasChanged 方法将返回 false
 int countObservers() 
          返回 Observable 对象的观察者数目。
 void deleteObserver(Observer o) 
          从对象的观察者集合中删除某个观察者。
 void deleteObservers() 
          清除观察者列表,使此对象不再有任何观察者。
 boolean hasChanged() 
          测试对象是否改变。
 void notifyObservers() 
          如果 hasChanged 方法指示对象已改变,则通知其所有观察者,并调用 clearChanged 方法来指示此对象不再改变。
 void notifyObservers(Object arg) 
          如果 hasChanged 方法指示对象已改变,则通知其所有观察者,并调用 clearChanged 方法来指示此对象不再改变。
protected  void setChanged() 
          标记此 Observable 对象为已改变的对象;现在 hasChanged 方法将返回 true

  示例: 监听成员变量变化

public class PersonOrg {
private String name;
private String sex;
private int age; public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public String getSex() {
return sex;
} public void setSex(String sex) {
this.sex = sex;
} public int getAge() {
return age;
} public void setAge(int age) {
this.age = age;
}
}

  步骤一、监听成员变量name,sex,age的变化,在数值变化是,执行我们的操作,所以Person就是被观察者,所以被观察者必须继承Observable,而Observable中有这三个方法:

  1、notifyObservers() : 如果 hasChanged 方法指示对象已改变,则通知其所有观察者,并调用 clearChanged 方法来指示此对象不再改变。

    这个方法是通知观察者被观察者是否改变的,只要hasChanged()方法指示的对象改变,就会调用观察者中的方法。

  2、hasChanged() : 测试对象是否改变。

  3、setChanged() :标记此 Observable 对象为已改变的对象;现在 hasChanged 方法将返回 true

  所以,如果想观察成员变量是否改变,就要在set方法中,执行setChanged()与notifyObservers()

  所以,被观察者应该改为:

public class Person extends Observable {
private String name;
private String sex;
private int age; public String getName() {
return name;
} public void setName(String name) {
this.name = name;
this.setChanged();
this.notifyObservers();
} public String getSex() {
return sex;
} public void setSex(String sex) {
this.sex = sex;
this.setChanged();
this.notifyObservers();
} public int getAge() {
return age;
} public void setAge(int age) {
this.age = age;
this.setChanged();
this.notifyObservers();
}
}

  步骤二、有了被观察者,就要有观察者,观察者必须实现java.util包下的Observer接口,并重写update(Observable o, Object arg)方法,当被观察者改变时,就会执行update()方法

public class MyObserver implements Observer {

    @Override
public void update(Observable o, Object arg) {
System.out.println("对象已改变");
}
}

  现在,就可以执行看一看了。不过在执行set()方法之前一定要使用addObserver(Observer o) 这个方法注册观察者,不然不会生效。

  使用 测试

    @Test
public void update() {
Person person = new Person();
//注册观察者
person.addObserver(new MyObserver());
person.setName("小明");
person.setSex("男");
person.setAge(18);
}

  输出:

对象已改变
对象已改变
对象已改变

  当然可以注册多个观察者

         //注册观察者
person.addObserver(new MyObserver());
person.addObserver(new MyObserver());

  更多使用:三个方法deleteObserver(Observer o) ,deleteObservers() ,countObservers()

    @Test
public void update2() {
Person person = new Person();
//注册观察者
MyObserver myObserver = new MyObserver();
person.addObserver(myObserver);
person.addObserver(new MyObserver());
//获得当前对象已注册的观察者数目
person.countObservers();
//删除指定的一个观察者
person.deleteObserver(myObserver);
//删除该对象全部观察者
person.deleteObservers(); person.setName("小明");
person.setSex("男");
person.setAge(18);
}

二、扩展

2.1、 java.awt.Event

2.2、org.springframework.web.context.request.RequestContextListener、ServletRequestListener、EventListener
监听器是观察者模式的实现一种

2.3、org.springframework.beans.factory.parsing.ReaderEventListener

2.4、google Guava之EventBus

增加pom引入

        <dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>26.0-jre</version>
</dependency>

  EventBus是Guava的事件处理机制,是设计模式中的观察者模式(生产/消费者编程模型)的优雅实现,在应用中可以处理一些异步任务。对于事件监听和发布订阅模式,EventBus是一个非常优雅和简单解决方案,我们不用创建复杂的类和接口层次结构。

  

  EventBus实际上是一个消息队列,Event Source发送一个消息到EventBus,然后再由EventBus将消息推送到所监听的Listener。

如上述示例使用guava改写

1、创建Listener

可以通过@Subscribe注解将任意的类的方法变为一个Listener。

public class PersonGuavaListener {
@Subscribe
public void doAction(final String event) {
System.out.println("对象发生变化:" + event);
}
}

2、创建EventBus并发送消息

public class PersonGuava {
EventBus eventBus = new EventBus();
private String name;
private String sex;
private int age; public PersonGuava() {
//注册Listener
eventBus.register(new PersonGuavaListener());
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
//向订阅者发送消息
eventBus.post("Simple Event:name:"+name);
} public String getSex() {
return sex;
} public void setSex(String sex) {
this.sex = sex;
//向订阅者发送消息
eventBus.post("Simple Event:sex:"+sex);
} public int getAge() {
return age;
} public void setAge(int age) {
this.age = age;
//向订阅者发送消息
eventBus.post("Simple Event:age:"+age);
}
}

测试

    @Test
public void test() {
PersonGuava person = new PersonGuava();
person.setName("李宏旭");
person.setAge(30);
person.setSex("男");
}

输出  

对象发生变化:Simple Event:name:李宏旭
对象发生变化:Simple Event:age:30
对象发生变化:Simple Event:sex:男

由于EventBus是将消息队列放入到内存中的,listener消费这个消息队列,故系统重启之后,保存或者堆积在队列中的消息丢失。

fd

004-行为型-03-观察者模式(Observer)的更多相关文章

  1. 【设计模式】行为型03观察者模式(Observer Pattern)

    记得16年初第一次学习了23种设计模式,但是除了少数几个简单的外,其他的很多都是学了个似懂非懂,以至于有人问起甚至说不上来,现在想想,其实就是没看懂而已.例如观察者模式,其实原理很简单,但是当时并没有 ...

  2. 设计模式 ( 十六 ) 观察者模式Observer(对象行为型)

    设计模式 ( 十六 ) 观察者模式Observer(对象行为型) 1.概述 一些面向对象的编程方式,提供了一种构建对象间复杂网络互连的能力.当对象们连接在一起时,它们就可以相互提供服务和信息. 通常来 ...

  3. 观察者模式 Observer 发布订阅模式 源 监听 行为型 设计模式(二十三)

    观察者模式 Observer 意图 定义对象一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖他的对象都得到通知并自动更新. 别名:依赖(Dependents),发布订阅(Publish-Su ...

  4. python设计模式---行为型之观察者模式

    比较常用咯~~ from django.test import TestCase from abc import ABCMeta, abstractmethod # 行为型设计模式---观察者模式 c ...

  5. 行为型模式之Observer模式

    观察者模式(又被称为发布-订阅模式.模型-视图模式.源-收听者模式或从属者模式) 观察者模式中,一个目标对象管理所有依赖于它的观察者对象,并且在它本身的状态改变时主动发出通知. 应用场景 拍卖会可以认 ...

  6. 设计模式 - 观察者模式(Observer Pattern) 详细说明

    观察者模式(Observer Pattern) 详细说明 本文地址: http://blog.csdn.net/caroline_wendy/article/details/26583157 版权全部 ...

  7. 乐在其中设计模式(C#) - 观察者模式(Observer Pattern)

    原文:乐在其中设计模式(C#) - 观察者模式(Observer Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 观察者模式(Observer Pattern) 作者:weba ...

  8. 设计模式 - 观察者模式(Observer Pattern) 详细解释

    观察者模式(Observer Pattern) 详细解释 本文地址: http://blog.csdn.net/caroline_wendy/article/details/26583157 版权全部 ...

  9. java设计模式--观察者模式(Observer)

    java设计模式--观察者模式(Observer) java设计模式--观察者模式(Observer) 观察者模式的定义: 定义对象间的一种一对多的依赖关系.当一个对象的状态发生改变时,所有依赖于它的 ...

  10. 8.5 GOF设计模式四: 观察者模式Observer

    GOF设计模式四: 观察者模式Observer  现实中遇到的问题  当有许多不同的客户都对同一数据源感兴趣,对相同的数据有不同的处理方式,该如 何解决?5.1 定义: 观察者模式  观察者模式 ...

随机推荐

  1. 神经网络(9)--如何求参数: backpropagation algorithm(反向传播算法)

    Backpropagation algorithm(反向传播算法) Θij(l) is a real number. Forward propagation 上图是给出一个training examp ...

  2. 行为型模式(八) 职责链模式(Chain of Responsibility)

    一.动机(Motivate) 在软件构建过程中,一个请求可能被多个对象处理,但是每个请求在运行时只能有一个接受者,如果显示指定,将必不可少地带来请求发送者与接受者的紧耦合.如何使请求的发送者不需要指定 ...

  3. 洛谷 P1955 [NOI2015]程序自动分析 题解

    每日一题 day22 打卡 Analysis 离散化+并查集 先离散化所有的约束条件,再处理所有e=1的条件,将i的祖先和j的祖先合并到一个集合中:e=0时,如果i的祖先与j的祖先在同一个集合中,说明 ...

  4. linux 登录后有时候会出现-bash-4.1$

    转载自https://blog.csdn.net/jiedao_liyk/article/details/78470498 linux登录后有时候会出现-bash-4.1$ 造成这样的原因: 与这个用 ...

  5. Python + Apache Kylin 让数据分析更加简单!

    现如今,大数据.数据科学和机器学习不仅是技术圈的热门话题,也是当今社会的重要组成.数据就在每个人身边,同时每天正以惊人的速度快速增长,据福布斯报道:到 2025 年,每年将产生大约 175 个 Zet ...

  6. 第三节.vue.js属性与方法

    1. <!DOCTYPE html><html><head><meta charset="UTF-8"><title>I ...

  7. loj #6191. 「美团 CodeM 复赛」配对游戏 期望dp

    题意:有一个栈,随机插入 $n$ 次 $0$/$1$ 如果栈顶是 $1$,然后插入 $0$,则将这两个元素都弹出,否则,插入栈顶. 求:$n$ 次操作后栈中期望的元素个数. 我们发现,按照上述弹栈方式 ...

  8. C利用time函数实现简单的定时器

    //定时器 #include <stdio.h> #include <time.h> #include <stdlib.h> int main(int num, c ...

  9. Problem 7 树状数组+转化

    $des$有一棵 $n$ 个点的以 $1$ 为根的树, 以及 $n$ 个整数变量 $x_i$ .树上 $i$ 的父亲是 $f_i$ ,每条边 $(i,f_i)$ 有一 个权值 $w_i$ ,表示一个方 ...

  10. 第2组 团队Git现场编程实战

    目录 组员职责分工(1 2分) github 的提交日志截图(2 1分) 程序运行截图(3 3分) 程序运行环境(4 1分) GUI界面(5 5分) 基础功能实现(6 10分) 鼓励有想法且有用的功能 ...