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 定义: 观察者模式 观察者模式 ...
随机推荐
- linux网络编程之socket编程(四)
经过两周的等待,终于可以回归我正常的学习之旅了,表哥来北京了在我这暂住,晚上回家了基本在和他聊天,周末带他在北京城到处乱转,几乎剥夺了我自由学习的时间了,不过,亲人之情还是很难得的,工作学习并不是生活 ...
- IDEA -01 -忽略指定文件夹 -防止加载Vue-cli执行"npm install"命令后的项目时卡死
问题描述 Vue的"npm install" 命令执行后,会生成一个很大的目录层次的"node_modules",文件十分繁多; idea加载这个项目下的文件夹 ...
- 【Java】Unicode & UTF-8 & UTF-16 & UTF-32
Unicode Unicode(统一码.万国码.单一码)是计算机科学领域里的一项业界标准,包括字符集.编码方案等.Unicode 是为了解决传统的字符编码方案的局限而产生的,它为每种语言中的每个字符设 ...
- 在springboot项目中使用swaggerui
在pom.xml文件中配置(用的2.6.1版本,2.9.2有点丑) <properties> <!--<spring.swagger2.version>2.9.2< ...
- linux下新磁盘创建lvm、扩容lvm
1.首先查看磁盘fdisk -l2.进入磁盘fdisk /dev/sdbn 创建新磁盘p 创建主分区创建分区ID 1-4为主分区根据提示选择磁盘开始位置(默认空格就好)选择结束位置(新增磁盘大小)t ...
- jQuery弹出提示信息自动消失简洁版
// 在bootstrap中可以,可以使用如下方式实现弹出提示信息自动消失,如果没有使用bootstrap框架,可以自定义样式 //tip是提示信息,type:'success'是成功信息,'dang ...
- learning java StringBuilder 类
StringBuilder s1 = new StringBuilder(); s1.append("panzidong"); s1.insert(,"hong,&quo ...
- SpreadJS 复制行
参考:https://www.cnblogs.com/yeyuqian/p/10750441.html 核心代码: //例子:复制第一行(10列) 复制到 第二行var fromRanges = ne ...
- Pytest权威教程26-示例和自定义技巧
目录 示例和自定义技巧 返回: Pytest权威教程 示例和自定义技巧 这是一个(不断增长的)示例列表.如果你需要更多示例或有疑问,请联系我们.另请参阅包含许多示例代码段的 综合文档.此外,stack ...
- [DOM] Input elements should have autocomplete attributes (suggested: autocomplete='tel', confirm at
译文概要:输入元素应该有自动完成的属性,比如: autocomplete=’tel’. autocomplete 用途: 此功能主要是记住输入内容,下次提交表单或者浏览器回退后,还能保持表单内容不变. ...