第十三篇:观察者模式 : 一支穿云箭,千军万马来相见

2024-01-10 01:59

本文主要是介绍第十三篇:观察者模式 : 一支穿云箭,千军万马来相见,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

小时候一块钱就可以在录像厅看一天电影,印象里最喜欢星爷的电影,特别搞笑。

后来渐渐长大,接触了一些人和事,略微懂了他的那些苦笑、狂笑和欲哭无泪。

我喜欢的演员很多,唯独星爷,能让我看到他的照片,有种想哭的感觉。

这里写图片描述

星爷,may the god bless you.


最近又看了遍《功夫》,其中有一幕:

这里写图片描述

阿星装比失败,不曾想引来了斧头帮,斧头帮老大一支穿云箭,真的是千军万马来相见,帅呆了!

这里写图片描述

骨子里也是个古惑仔的我好崇拜这种场景!太帅了!那,这是怎么做到的呢?

  • 首先我得加入斧头帮,成为斧头帮一份子
  • 然后去登记,有啥事方便通知
  • 等老大一发穿云箭
  • 我跟其他小弟就赶紧出现

用代码实现一下:

1.首先定义 斧头帮老大 AxeGangBoss:

/*** description: 斧头帮老大,消息发布者,继承 Observable* <br/>* author: shixinzhang* <br/>* data: 9/20/2016*/
public class AxeGangBoss extends Observable {private String mName;public AxeGangBoss(String name) {mName = name;}/*** 在需要通知小弟的时候调用 setChanged()方法,表明有更新* 然后提醒所有小弟* @param msg*/public void sendMsg(String msg) {//表示有更新setChanged();notifyObservers(msg);}public String getName() {return mName;}public void setName(String name) {mName = name;}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

斧头帮老大是消息发布者,当有情况时就调用 sendMsg(…) 方法给小弟发消息。他继承自 Java 源代码提供的 Observable :

public class Observable {List<Observer> observers = new ArrayList<Observer>();boolean changed = false;public Observable() {}public void addObserver(Observer observer) {if (observer == null) {throw new NullPointerException("observer == null");}synchronized (this) {if (!observers.contains(observer))observers.add(observer);}}protected void clearChanged() {changed = false;}public int countObservers() {return observers.size();}public synchronized void deleteObserver(Observer observer) {observers.remove(observer);}public synchronized void deleteObservers() {observers.clear();}public boolean hasChanged() {return changed;}public void notifyObservers() {notifyObservers(null);}@SuppressWarnings("unchecked")public void notifyObservers(Object data) {int size = 0;Observer[] arrays = null;synchronized (this) {if (hasChanged()) {clearChanged();size = observers.size();arrays = new Observer[size];observers.toArray(arrays);}}if (arrays != null) {for (Observer observer : arrays) {observer.update(this, data);}}}protected void setChanged() {changed = true;}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66

Observable 里保存着一个 Observer 的集合,然后提供了添加、删除、提醒等方法。其中重要的是 notifyObservers(…) 方法,当确定出事了(changed 为 true)时 ,挨个通知小弟。 
Observer 是一个接口,规定了小弟收到消息的方法 update(…):

public interface Observer {void update(Observable observable, Object data);
}
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

2.定义斧头帮小弟 AxeGangPeople,小弟需要按规矩来,实现 Observer 接口:

/*** description: 斧头帮小弟,订阅者,实现 Observer 接口* <br/>* author: shixinzhang* <br/>* data: 9/20/2016*/
public class AxeGangPeople implements Observer {String mName;public AxeGangPeople(String name){mName = name;}/*** 必须实现的方法,当消息发布者发出通知后,会调用这个方法* @param observable* @param data*/@Overridepublic void update(Observable observable, Object data) {AxeGangBoss writer;if (observable instanceof AxeGangBoss) {writer = (AxeGangBoss) observable;System.out.println(getName() + " 收到来自 " + writer.getName() + " 的消息: " + data.toString());}}public String getName() {return mName;}public void setName(String name) {mName = name;}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

3.然后小弟去老大那登记,老大有消息了就射穿云箭:

    @Testpublic void testSendMsg() throws Exception {//创建一个斧头帮老大AxeGangBoss shixinzhang = new AxeGangBoss("张拭心");//创建两个小弟AxeGangPeople niefeng = new AxeGangPeople("聂风");AxeGangPeople bujingyun = new AxeGangPeople("步惊云");//老大觉得可以,收入麾下shixinzhang.addObserver(niefeng);shixinzhang.addObserver(bujingyun);//老大出事了,赶紧射箭!shixinzhang.sendMsg("我有难了,快来救我!");}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

4.运行结果: 
这里写图片描述

这种 一对多的通知场景 就是传说中的观察者模式

观察者模式

1.定义:

又称“发布-订阅模式”,定义了一种一对多的依赖关系,一个被观察者持有多个观察者对象的引用,当被观察者状态发生改变时,通知所有观察者进行更新。

2.UML 图

这里写图片描述

  • 其中 Subject 是被观察者接口,即上文提到的 Observable ,持有一个观察者接口集合的引用,定义了观察者的添加、删除以及提醒;

  • ConcreteSubject 实现了被观察者接口,即上文的斧头帮老大 AxeGangBoss,在一定情况下提醒观察者更新;

  • Observer 是观察者抽象类,定义了更新 update 方法;
  • ConcreteObserver 是具体观察者,即上文的小弟 AxeGangPeople,重写 update 方法,进行触发操作。里面有时需要持有一个 Subject 的引用。

3.场景:

有的时候一个状态值会影响许多逻辑,比如电商类软件的位置信息,如果用户切换位置,需要显示对应城市的商品信息、活动、附件的人等等,这时使用观察者模式可以减少对应模块的代码逻辑,直接写好回调方法,等待被回调就好,耦合度降低很多。

4.备注

代码地址点这里

下一篇博客我们通过查看 ListView 源码中的观察者模式 来加深理解。

这篇关于第十三篇:观察者模式 : 一支穿云箭,千军万马来相见的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/589174

相关文章

Redis Cluster模式配置

《RedisCluster模式配置》:本文主要介绍RedisCluster模式配置,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录分片 一、分片的本质与核心价值二、分片实现方案对比 ‌三、分片算法详解1. ‌范围分片(顺序分片)‌2. ‌哈希分片3. ‌虚

RabbitMQ工作模式中的RPC通信模式详解

《RabbitMQ工作模式中的RPC通信模式详解》在RabbitMQ中,RPC模式通过消息队列实现远程调用功能,这篇文章给大家介绍RabbitMQ工作模式之RPC通信模式,感兴趣的朋友一起看看吧... 目录RPC通信模式概述工作流程代码案例引入依赖常量类编写客户端代码编写服务端代码RPC通信模式概述在R

SQL Server身份验证模式步骤和示例代码

《SQLServer身份验证模式步骤和示例代码》SQLServer是一个广泛使用的关系数据库管理系统,通常使用两种身份验证模式:Windows身份验证和SQLServer身份验证,本文将详细介绍身份... 目录身份验证方式的概念更改身份验证方式的步骤方法一:使用SQL Server Management S

Redis高可用-主从复制、哨兵模式与集群模式详解

《Redis高可用-主从复制、哨兵模式与集群模式详解》:本文主要介绍Redis高可用-主从复制、哨兵模式与集群模式的使用,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝... 目录Redis高可用-主从复制、哨兵模式与集群模式概要一、主从复制(Master-Slave Repli

一文带你搞懂Redis Stream的6种消息处理模式

《一文带你搞懂RedisStream的6种消息处理模式》Redis5.0版本引入的Stream数据类型,为Redis生态带来了强大而灵活的消息队列功能,本文将为大家详细介绍RedisStream的6... 目录1. 简单消费模式(Simple Consumption)基本概念核心命令实现示例使用场景优缺点2

Nginx location匹配模式与规则详解

《Nginxlocation匹配模式与规则详解》:本文主要介绍Nginxlocation匹配模式与规则,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、环境二、匹配模式1. 精准模式2. 前缀模式(不继续匹配正则)3. 前缀模式(继续匹配正则)4. 正则模式(大

Linux系统配置NAT网络模式的详细步骤(附图文)

《Linux系统配置NAT网络模式的详细步骤(附图文)》本文详细指导如何在VMware环境下配置NAT网络模式,包括设置主机和虚拟机的IP地址、网关,以及针对Linux和Windows系统的具体步骤,... 目录一、配置NAT网络模式二、设置虚拟机交换机网关2.1 打开虚拟机2.2 管理员授权2.3 设置子

SpringBoot如何通过Map实现策略模式

《SpringBoot如何通过Map实现策略模式》策略模式是一种行为设计模式,它允许在运行时选择算法的行为,在Spring框架中,我们可以利用@Resource注解和Map集合来优雅地实现策略模式,这... 目录前言底层机制解析Spring的集合类型自动装配@Resource注解的行为实现原理使用直接使用M

C#原型模式之如何通过克隆对象来优化创建过程

《C#原型模式之如何通过克隆对象来优化创建过程》原型模式是一种创建型设计模式,通过克隆现有对象来创建新对象,避免重复的创建成本和复杂的初始化过程,它适用于对象创建过程复杂、需要大量相似对象或避免重复初... 目录什么是原型模式?原型模式的工作原理C#中如何实现原型模式?1. 定义原型接口2. 实现原型接口3

大数据spark3.5安装部署之local模式详解

《大数据spark3.5安装部署之local模式详解》本文介绍了如何在本地模式下安装和配置Spark,并展示了如何使用SparkShell进行基本的数据处理操作,同时,还介绍了如何通过Spark-su... 目录下载上传解压配置jdk解压配置环境变量启动查看交互操作命令行提交应用spark,一个数据处理框架