设计模式:观察者模式

article/2025/9/24 15:43:14

1.1 观察者模式

1.1.1 观察者模式的引入案例

天气预报在现实生活中的有着非常广泛的应用,在即将发生灾害天气时,专用的气象广播电台可用一定波长的信号,使这种收音机自动开启呼叫,这样,入睡的人也能被其信号唤醒,收听到灾害性天气警报,这对及时采取预防措施提供了可能性。

当我们在实现一个气象信息应用的时候,气象站实时监测并更新天气信息,与此同时终端各种用户界面要实时显示最新的天气信息,具体要求如下:

  1. 气象站可以将每天测到的温度、湿度、气压、PM2.5等以公告的形式发布到自己的网站或第三方。

  2. 有对外的接口可以被其他系统所调用,当气象站数据更新后,天气接口程序去获取最新天气数据,然后将数据分发给所有订阅过“天气日报”程序的用户,及时更新数据。

查看大图

1.1.2 观察者模式动机分析

观察者模式的模式动机是建立一种对象与对象之间的依赖关系,一个对象发生改变时将自动通知其他对象,其他对象将相应作出反应。在此,发生改变的对象称为观察目标,而被通知的对象称为观察者,一个观察目标可以对应多个观察者,而且这些观察者之间没有相互联系,可以根据需要增加和删除观察者,使得系统更易于扩展。

1.1.3 观察者模式定义

观察者模式(Observer Pattern):定义对象间的一种一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖的对象皆得到通知并被自动更新。观察者模式又叫发布-订阅(Publish/Subscribe)模式、模式-视图(Model/View)模式、源-监听器(Source/Listener)模式或丛书者(Dependents)模式。

观察者模式是一种对象行为型模式。

Subject:抽象主题(被观察者),每一个主题可以有多个观察者,并将所有观察者对象的引用保存在一个集合里,被观察者提供一个接口,可以增加和删除观察者角色。

ConcreteSubject:具体主题,将有关状态存入具体观察者对象,在主题发生改变时,给所有的观察者发出通知。

Observer:抽象观察者,为所有的具体观察者定义一个更新接口,该接口的作用是在收到主题的通知时能够及时的更新自己。

ConcreteObserver:具体观察者,实现抽象观察者角色定义的更新接口,以便使本身的状态与主题状态相协调。如果需要,具体观察者角色可以保存一个指向具体主题角色的引用。

1.1.4 观察者模式类图

image-20220516154822561

1.1.5 观察者模式类图对应的源码框架

1.1.5.1.定义观察者接口

public interface Observer {void response();
}

1.1.5.2.定义被观察者接口

public abstract class Subject {protected Vector<Observer> observers;public void add(Observer observer){if(observers == null){observers = new Vector<>();}this.observers.add(observer);}public void removeObserver(Observer observer){observers.remove(observer);}public abstract void notifyObserver();public abstract void doSomething();}

1.1.5.3.定义具体的被观察者

public class ConcreteSubject extends Subject {@Overridepublic void notifyObserver() {for (Observer observer : observers) {observer.response();}}@Overridepublic void doSomething() {System.out.println("被观察者事件发生改变");notifyObserver();}
}

1.1.5.4.定义具体的观察者

public class ConcreteObserver1 implements Observer {@Overridepublic void response() {System.out.println("观察者1收到信息...");}
}public class ConcreteObserver2 implements Observer {@Overridepublic void response() {System.out.println("观察者2收到信息...");}
}

1.1.5.5.定义客户端

public class Client {public static void main(String[] args) {Subject sub = new ConcreteSubject();sub.add(new ConcreteObserver1());sub.add(new ConcreteObserver2());sub.doSomething();}
}

1.1.5.6.运行测试

image-20220516155542063

1.1.6 观察者模式案例及对应的源码(可运行)

当我们在实现一个气象信息应用的时候,气象站实时监测并更新天气信息,与此同时终端各种用户界面要实时显示最新的天气信息,具体要求如下:

1.气象站可以将每天测到的温度、湿度、气压、PM2.5等以公告的形式发布到自己的网站或第三方。

2.有对外的接口可以被其他系统所调用,当气象站数据更新后,天气接口程序去获取最新天气数据,然后将数据分发给所有订阅过“天气日报”程序的用户,及时更新数据。

image-20220516155529553

1.1.6.1抽象目标类

public abstract class Subject {protected Vector<Observer> observers;public abstract void addObserver(Observer observer);public abstract void removeObserver(Observer observer);public abstract void notifyObserver();}

1.1.6.2.观察者类

public interface Observer {void response();
}

1.1.6.3.气象台类

public class WeatherData extends Subject{private float temperature;private float pressure;private float humidity;@Overridepublic void addObserver(Observer observer) {if(observers == null){observers = new Vector<>();}observers.add(observer);}@Overridepublic void removeObserver(Observer observer) {int i = observers.indexOf(observer);if(i >= 0){observers.remove(i);}}@Overridepublic void notifyObserver() {for (Observer observer : observers) {observer.response();}}public void measurementChanged(){notifyObserver();}public void setMeasurements(float temperature,float pressure,float humidity){this.temperature = temperature;this.pressure = pressure;this.humidity = humidity;System.out.println("当前状况:温度->"+this.temperature+"华氏度,气压->"+this.pressure+",湿度->"+this.humidity);measurementChanged();}
}

1.1.6.4.用户类

public class User implements Observer {private String name;@Overridepublic void response() {System.out.println("用户:"+name+" 接收到气象站更新的数据。");}public User(String name) {this.name = name;}
}

1.1.6.5.客户测试类

public class Client {public static void main(String[] args) {WeatherData weatherData = new WeatherData();User user1 = new User("张三");User user2 = new User("李四");User user3 = new User("王五");weatherData.addObserver(user1);  //张三订阅weatherData.addObserver(user2);  //李四订阅weatherData.setMeasurements(80,  30.4f,65);weatherData.setMeasurements(82,  29.2f,70);weatherData.setMeasurements(78,  40.4f,78);}
}

1.1.6.6.运行截图

image-20220516155511567

1.1.7 观察者模式在JDK、Spring、SpringMVC、Springboot或者Android框架源码任何第三方应用的类图及源码分析。

观察者模式在JDK、Spring、Springboot中都有着广泛的应用,如JDK的事件机制、Spring及Springboot的事件监听机制,下面就Spring中的观察者模式展开分析。

1.1.7.1 观察者模式在Spring中的源码分析

Spring中的事件监听机制,很多人也叫做监听器模式,其实是在观察者模式中对观察者模式实现了更加的抽象化和细化,其中主要有四个角色:

ApplicationListener:事件监听器,等同于观察者Observer,实现类继承该接口,重写onApplicationEvent方法,处理对事件发生的响应。

ApplicationEvent:事件,是所有事件对象的父类,ApplicationEvent继承自jdk的EventObject,所有的事件继承ApplicationEvent,监听器监听到事件后作出响应,spring这里进行了抽象,抽象出了这个具体的接口,运用起来更加灵活,扩展性更强。

ApplicationEventMulticaster:事件多路广播器,用于事件监听器的注册和事件的广播。监听器的注册就是通过它来实现的,它的作用是把Applicationcontext发布的Event广播给他的监听器列表,下图是ApplicationEventMulticaster的类结构,与观察者模式的抽象目标相似。

image-20220516155458624

ApplicationEventPublisher:事件发布者,即事件源通过该接口的publishEvent方法发布时间,所有的应用上下文都具备事件发布能力,ApplicationContext实现了该接口。

image-20220516155449046

Spring****事件监听机制流程:

image-20220516155408548

1.流程分为两个阶段

​ (1)一个是启动Spring容器

​ (2)另外一个是我们触发事件的时候

2.核心还是事件广播器ApplicationEventMulticaster(这里实际指的是它的实现类ApplicationEventMulticaster,SimpleApplicationEventMulticaster)

3.增加监听器是在启动Spring容器时候完成的(图中紫红色的部分)。这也是Spring容器的核心位置。这两个addxxx分别是:

(1)增加普通的监听器,即通过实现ApplicationListener实现的监听器

(2)增加使用注解(@EventListener)实现的监听器

4.事件发布。这是我们写程序可触及到的一部分流程。核心是ApplicationEventPublisher。这里会首先去调用事件广播器的getApplicationListeners方法,拿到所有的监听器(由于前面启动时已经加载里所有监听器,所以这里可以拿到),然后逐个调用监听器内的方法。

总结

1.从AbstractApplicationContext类中的Set<ApplicationListener<?>> applicationListeners取出用户添加的监听器ApplicationListener,添加到多路广播器中

2.从spring工厂中取出符合条件的ApplicationListener,添加到多路广播器中

3.对早期添加在earlyApplicationEvents中的事件进行发布

1.1.7.2 观察者模式在Spring中事件监听机制中的类图

image-20220516155323094

1.1.8 观察者模式扩展分析

1.1.8.1 观察者模式的两种实现方式

(1)拉取模式:目标角色在发生变化后,仅仅告诉观察者角色“我变化了”,观察者角色如果想要知道具体的变化细节,则就要自己从目标角色的接口中得到,这种模式称为拉取模式,就是说变化的信息是观察者角色主动从目标角中“拉”出来的。

(2)推送模式:目标角色发生变化时,通知观察者的同时,通过参数将变化的细节传递到观察者角色中去。

这两种模式的使用取决于系统设计,如果目标角色比较复杂,并且观察者角色进行更新时必须得到一些具体变化的信息,则“推模式”比较合适,如果目标角色比较简单,则“拉模式”就很合适啦。

1.1.8.2 观察者模式与发布订阅模式的区别

发布与订阅模式和观察者模式有以下不同:

  1. 观察者模式中,观察者和主题都知道对方的存在;而在发布与订阅模式中, 生产者与消费者不知道对方的存在,它们之间通过频道进行通信。

  2. 观察者模式是同步的,当事件触发时,主题会调用观察者的方法,然后等待方法返回;而发布与订阅模式是异步的,生产者向频道发送一个消息之后, 就不需要关心消费者何时去订阅这个消息,可以立即返回。

img

1.1.9 观察者模式优缺点分析

优点:一个观察目标可以对应多个观察者,而这些观察者之间没有相互联系,所以能够根据需要增加和删除观察者,使得系统更易于扩展,符合开闭原则;并且观察者模式让目标对象和观察者松耦合,虽然彼此不清楚对方的细节,但依然可以交互,目标对象只知道一个具体的观察者列表,并不认识一个具体的观察者,它只知道他们都有一个共同的接口。

观察者模式支持广播通信。

观察者模式符合“开闭原则”的要求。

缺点:观察者模式的缺点在于如果存在很多个被观察者的话,那么将需要花费一定时间通知所有的观察者,如果观察者与被观察者之间存在循环依赖的话,那么可能导致系统崩溃,并且观察者模式没有对应的机制让观察者知道被观察者对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。


http://chatgpt.dhexx.cn/article/jmwKp7dZ.shtml

相关文章

《设计模式》之观察者模式

一、什么是观察者模式 观察者模式又称为 发布-订阅模式&#xff0c;定义了对象之间一对多依赖关系&#xff0c;当目标对象(被观察者)的状态发生改变时&#xff0c;它的所有依赖者(观察者)都会收到通知。一个观察目标可以对应多个观察者&#xff0c;而这些观察者之间没有相互联…

kotlin——观察者模式

ObserverManager类&#xff1a; /*** 1、观察者模式管理类*/ class ObserverManager : SubjectListener {/*** 观察者集合*/private val list ArrayList<ObserverListener>()override fun add(observerListener: ObserverListener) {// 加入队列list.add(observerListe…

观察者模式及其应用场景

观察者模式&#xff08;Observer Design Pattern&#xff09;,也叫做发布订阅模式&#xff08;Publish-Subscribe Design Pattern&#xff09;、模型-视图&#xff08;Model-View&#xff09;模式、源-监听器&#xff08;Source-Listener&#xff09;模式、从属者&#xff08;D…

C++观察者模式

C观察者模式 当对象间存在一对多关系时&#xff0c;则使用观察者模式&#xff08;observer pattern&#xff09;。比如&#xff0c;当一个对象被修改时&#xff0c;则会自动通知发依赖它的对象。观察者模式属于行为型模式。 Observer模式是应用最多、影响最广的设计模式之一&am…

Android开发模式之观察者模式

目录 一、定义 1.观察者模式 2.UML类图 3.观察者模式中的角色 二、使用场景 三、简单实现 四、观察者模式在java.util包中的应用 五、观察者模式在Button中的应用 六、观察者模式在ListView中的应用 七、观察者模式的优缺点 观察者模式的优点 观察者模式的缺点 一、…

java设计模式-观察者模式

观察者模式介绍&#xff1a; 观察者模式&#xff08;有时又被称为发布/订阅模式&#xff09;是软件设计模式的一种。在此种模式中&#xff0c;一个目标对象管理所有相依于它的观察者对象&#xff0c;并且在它本身的状态改变时主动发出通知。这通常透过呼叫各观察者所提供的方法…

观察者模式(Observer) 简介

一, 观察者模式(Observer) 的定义 观察者模式: 定义了一种 1对多 的依赖关系, 让多个观察者对象同时监听1个主题对象. 这个主题对象在状态发生变化时, 会通知所有的观察者对象, 使它们能够同时更新自己. 稍微解释一下 这个1 对多 的依赖关系. 1对多 这个关键词我们常常在DB …

观察者模式

第23章 观察者模式 一、观察者模式的基本介绍 观察者模式(Observer Pattern)&#xff1a;定义对象间的一种一对多依赖关系&#xff0c;使得每当一个对象状态发生改变时&#xff0c;其相关依赖对象皆得到通知并被自动更新。 观察者模式又叫做发布-订阅&#xff08;Publish/Subsc…

观察者模式(Observer Pattern)

一、什么是观察者模式 观察者模式是一种对象行为模式。它定义对象间的一种一对多的依赖关系&#xff0c;当一个对象(目标对象)的状态发生改变时&#xff0c;所有依赖于它的对象(观察对象)都得到通知并被自动更新。特点&#xff1a;被观察者和观察者一般是一对多的关系&#xf…

设计模式之观察者模式详解(附应用举例实现)

文章目录 1 观察者模式介绍2 观察者模式详解2.1 观察者模式结构2.2 观察者模式实现2.3 观察者模式应用举例 3 观察者模式与MVC 1 观察者模式介绍 “红灯停&#xff0c;绿灯行”。在这个过程中&#xff0c;交通信号灯是汽车的观察目标&#xff0c;而汽车则是观察者。随着交通信…

23种设计模式——观察者模式

目录 观察者模式&#xff08;Observer&#xff09; 理解 UML图 优缺点 观察者模式在各语言中的支持 Java C# 实例 小丑表演 办公室摸鱼 投资者与股票 观察者模式&#xff08;Observer&#xff09; 本质&#xff1a;触发联动 目标对象变化时&#xff0c;会通知所有登…

设计模式(五)观察者模式

相关文章 设计模式系列 1.观察者模式模式简介 定义 观察者模式&#xff08;又被称为发布-订阅&#xff08;Publish/Subscribe&#xff09;模式&#xff0c;属于行为型模式的一种&#xff0c;它定义了一种一对多的依赖关系&#xff0c;让多个观察者对象同时监听某一个主题对…

Win64 驱动内核编程-28.枚举消息钩子

枚举消息钩子 简单粘贴点百度的解释&#xff0c;科普下消息钩子&#xff1a; 钩子是WINDOWS中消息处理机制的一个要点&#xff0c;通过安装各种钩子&#xff0c;应用程序能够设置相应的子例程来监视系统里的消息传递以及在这些消息到达目标窗口程序之前处理它们。 钩子的种类很…

Anti 消息钩子注入

MSDN上对消息钩子的描述&#xff1a; The SetWindowsHookEx function installs an application-defined hook procedure into a hook chain. You would install a hook procedure to monitor the system for certain types of events. These events are associated either wit…

注入(4)--消息钩子注入(SetWindowsHookEX)

SetWindowsHookEx函数是微软提供给程序开发人员进行消息拦截的一个API。不过,他的功能不仅可以用作消息拦截,还可以进行DLL注入。 SetWindowsHookEx原型声明如下: WINUSERAPI HHOOK WINAPI SetWindowsHookExW(_In_ int idHook,_In_ HOOKPROC lpfn,_In_opt_ HINSTANCE hmod,…

DLL注入技术之消息钩子注入

消息钩子注入原理是利用Windows 系统中SetWindowsHookEx()这个API&#xff0c;他可以拦截目标进程的消息到指定的DLL中导出的函数&#xff0c;利用这个特性&#xff0c;我们可以将DLL注入到指定进程中。主要流程如下图所示 1&#xff0e;准备阶段 需要编写一个DLL&#xff…

关于采用消息钩子机制的透明加密的简单破解

采用消息钩子机制的透明加密方式在各大企业中很常见&#xff0c;简单实用。文件在磁盘上以密文方式存储&#xff0c;打开时首先被加密软件客户端注入的钩子&#xff08;hook&#xff09;截获&#xff0c;解密成明文后再提交给相应程序&#xff1b;保存时同样被钩子截获&#xf…

VC 消息钩子编程

分享一下我老师大神的人工智能教程&#xff01;零基础&#xff0c;通俗易懂&#xff01;http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章。分享知识&#xff0c;造福人民&#xff0c;实现我们中华民族伟大复兴&#xff01; 一、消息钩子的概念 1、基本概念 Windows应…

Windows消息钩子[键盘监控]

之前看书&#xff0c;看到一眼消息钩子&#xff0c;一直没实践&#xff0c;现在有空弄了下&#xff0c; 主要原理是利用windows自带SetWindowsHookEx API函数 HHOOK SetWindowsHookEx( int idHook, //hook形式 HOOKPROC lpfn //hook过程 HI…

一、C++反作弊对抗实战 (基础篇 —— 4.利用消息钩子注入DLL)

这里将主要用到Windows API函数SetWindowsHookEx,它是微软提供给程序开发人员进行消息拦截的一个API,不过它的功能不仅用作消息拦截,还可以进行DLL注入。 一、关于SetWindowsHookEx 提这个函数在微软官网MSDN文档中原型声明如下: SetWindowsHookExA function (winuser.h…