004-行为型-03-观察者模式(Observer)
一、概述
当对象间存在一对多关系时,则使用观察者模式(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)的更多相关文章
- 【设计模式】行为型03观察者模式(Observer Pattern)
记得16年初第一次学习了23种设计模式,但是除了少数几个简单的外,其他的很多都是学了个似懂非懂,以至于有人问起甚至说不上来,现在想想,其实就是没看懂而已.例如观察者模式,其实原理很简单,但是当时并没有 ...
- 设计模式 ( 十六 ) 观察者模式Observer(对象行为型)
设计模式 ( 十六 ) 观察者模式Observer(对象行为型) 1.概述 一些面向对象的编程方式,提供了一种构建对象间复杂网络互连的能力.当对象们连接在一起时,它们就可以相互提供服务和信息. 通常来 ...
- 观察者模式 Observer 发布订阅模式 源 监听 行为型 设计模式(二十三)
观察者模式 Observer 意图 定义对象一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖他的对象都得到通知并自动更新. 别名:依赖(Dependents),发布订阅(Publish-Su ...
- python设计模式---行为型之观察者模式
比较常用咯~~ from django.test import TestCase from abc import ABCMeta, abstractmethod # 行为型设计模式---观察者模式 c ...
- 行为型模式之Observer模式
观察者模式(又被称为发布-订阅模式.模型-视图模式.源-收听者模式或从属者模式) 观察者模式中,一个目标对象管理所有依赖于它的观察者对象,并且在它本身的状态改变时主动发出通知. 应用场景 拍卖会可以认 ...
- 设计模式 - 观察者模式(Observer Pattern) 详细说明
观察者模式(Observer Pattern) 详细说明 本文地址: http://blog.csdn.net/caroline_wendy/article/details/26583157 版权全部 ...
- 乐在其中设计模式(C#) - 观察者模式(Observer Pattern)
原文:乐在其中设计模式(C#) - 观察者模式(Observer Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 观察者模式(Observer Pattern) 作者:weba ...
- 设计模式 - 观察者模式(Observer Pattern) 详细解释
观察者模式(Observer Pattern) 详细解释 本文地址: http://blog.csdn.net/caroline_wendy/article/details/26583157 版权全部 ...
- java设计模式--观察者模式(Observer)
java设计模式--观察者模式(Observer) java设计模式--观察者模式(Observer) 观察者模式的定义: 定义对象间的一种一对多的依赖关系.当一个对象的状态发生改变时,所有依赖于它的 ...
- 8.5 GOF设计模式四: 观察者模式Observer
GOF设计模式四: 观察者模式Observer 现实中遇到的问题 当有许多不同的客户都对同一数据源感兴趣,对相同的数据有不同的处理方式,该如 何解决?5.1 定义: 观察者模式 观察者模式 ...
随机推荐
- 神经网络(9)--如何求参数: backpropagation algorithm(反向传播算法)
Backpropagation algorithm(反向传播算法) Θij(l) is a real number. Forward propagation 上图是给出一个training examp ...
- 行为型模式(八) 职责链模式(Chain of Responsibility)
一.动机(Motivate) 在软件构建过程中,一个请求可能被多个对象处理,但是每个请求在运行时只能有一个接受者,如果显示指定,将必不可少地带来请求发送者与接受者的紧耦合.如何使请求的发送者不需要指定 ...
- 洛谷 P1955 [NOI2015]程序自动分析 题解
每日一题 day22 打卡 Analysis 离散化+并查集 先离散化所有的约束条件,再处理所有e=1的条件,将i的祖先和j的祖先合并到一个集合中:e=0时,如果i的祖先与j的祖先在同一个集合中,说明 ...
- linux 登录后有时候会出现-bash-4.1$
转载自https://blog.csdn.net/jiedao_liyk/article/details/78470498 linux登录后有时候会出现-bash-4.1$ 造成这样的原因: 与这个用 ...
- Python + Apache Kylin 让数据分析更加简单!
现如今,大数据.数据科学和机器学习不仅是技术圈的热门话题,也是当今社会的重要组成.数据就在每个人身边,同时每天正以惊人的速度快速增长,据福布斯报道:到 2025 年,每年将产生大约 175 个 Zet ...
- 第三节.vue.js属性与方法
1. <!DOCTYPE html><html><head><meta charset="UTF-8"><title>I ...
- loj #6191. 「美团 CodeM 复赛」配对游戏 期望dp
题意:有一个栈,随机插入 $n$ 次 $0$/$1$ 如果栈顶是 $1$,然后插入 $0$,则将这两个元素都弹出,否则,插入栈顶. 求:$n$ 次操作后栈中期望的元素个数. 我们发现,按照上述弹栈方式 ...
- C利用time函数实现简单的定时器
//定时器 #include <stdio.h> #include <time.h> #include <stdlib.h> int main(int num, c ...
- Problem 7 树状数组+转化
$des$有一棵 $n$ 个点的以 $1$ 为根的树, 以及 $n$ 个整数变量 $x_i$ .树上 $i$ 的父亲是 $f_i$ ,每条边 $(i,f_i)$ 有一 个权值 $w_i$ ,表示一个方 ...
- 第2组 团队Git现场编程实战
目录 组员职责分工(1 2分) github 的提交日志截图(2 1分) 程序运行截图(3 3分) 程序运行环境(4 1分) GUI界面(5 5分) 基础功能实现(6 10分) 鼓励有想法且有用的功能 ...