观察者模式(二十)

news/2024/11/20 23:37:16/

相信自己,请一定要相信自己

上一章简单介绍了迭代器模式(十九), 如果没有看过, 请观看上一章

一. 观察者模式

引用 菜鸟教程里面 观察者模式介绍: https://www.runoob.com/design-pattern/observer-pattern.html

当对象间存在一对多关系时,则使用观察者模式(Observer Pattern)。

比如,当一个对象被修改时,则会自动通知依赖它的对象。观察者模式属于行为型模式

一.一 介绍

意图: 定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。

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

何时使用: 一个对象(目标对象)的状态发生改变,所有的依赖对象(观察者对象)都将得到通知,进行广播通知。

如何解决: 使用面向对象技术,可以将这种依赖关系弱化。

关键代码: 在抽象类里有一个 ArrayList 存放观察者们。

应用实例: 1、拍卖的时候,拍卖师观察最高标价,然后通知给其他竞价者竞价。 2、西游记里面悟空请求菩萨降服红孩儿,菩萨洒了一地水招来一个老乌龟,这个乌龟就是观察者,他观察菩萨洒水这个动作。

优点: 1、观察者和被观察者是抽象耦合的。 2、建立一套触发机制。

缺点:
1、如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。
2、如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。
3、观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。

使用场景:

  • 一个抽象模型有两个方面,其中一个方面依赖于另一个方面。将这些方面封装在独立的对象中使它们可以各自独立地改变和复用。
  • 一个对象的改变将导致其他一个或多个对象也发生改变,而不知道具体有多少对象将发生改变,可以降低对象之间的耦合度。
  • 一个对象必须通知其他对象,而并不知道这些对象是谁。
  • 需要在系统中创建一个触发链,A对象的行为将影响B对象,B对象的行为将影响C对象……,可以使用观察者模式创建一种链式触发机制。

注意事项: 1、JAVA 中已经有了对观察者模式的支持类。 2、避免循环引用。 3、如果顺序执行,某一观察者错误会导致系统卡壳,一般采用异步方式。


组成角色具体关系
抽象观察者角色Observer为所有的具体观察者定义一个接口,在得到主题通知时更新自己
具体观察者角色Baidu, Sina, User实现抽象观察者角色所需要的更新接口,一边使本身的状态与制图的状态相协调
抽象被观察者角色Subject一个抽象主题,它把所有对观察者对象的引用保存在一个集合中
具体被观察者角色WeatherDataSubject一个具体的主题,在集体主题的内部状态改变时,所有登记过的观察者发出通知

image-20230615184354714

二. 观察者实例

如观察天气的情况

二.一 观察的对象实体 Weather

@Data
@Builder
public class Weather {/**温度, 气压, 湿度*/private float temperature;private float pressure;private float humidity;
}

二.二 抽象观察者 Observer

public interface Observer {public void update (Weather weather);
}

二.三 具体观察者实现

二.三.一 百度网站

@Slf4j
public class BaiDu implements Observer{private Weather weather ;@Overridepublic void update(Weather weather) {this.weather = weather;display();}public void display (){if (weather == null) {return ;}log.info(">>>>>>>>>>>>>百度网站获取到天气数据,进行个性化操作");log.info(">>>温度: {}, 气压: {}, 湿度: {}", weather.getTemperature(),weather.getPressure(),weather.getHumidity());}}

二.三.二 新浪网站

@Slf4j
public class Sina implements Observer{private Weather weather ;@Overridepublic void update(Weather weather) {this.weather = weather;display();}public void display (){if (weather == null) {return ;}log.info(">>>>>>>>>>>>>新浪网站获取到天气数据,进行个性化操作");log.info(">>>温度: {}, 气压: {}, 湿度: {}", weather.getTemperature(),weather.getPressure(),weather.getHumidity());}}

二.三.三 订阅者

@Slf4j
public class User implements Observer{private Weather weather ;@Overridepublic void update(Weather weather) {this.weather = weather;display();}public void display (){if (weather == null) {return ;}log.info(">>>>>>>>>>>>>订阅用户获取到天气数据,进行个性化操作");log.info(">>>温度: {}, 气压: {}, 湿度: {}", weather.getTemperature(),weather.getPressure(),weather.getHumidity());}}

二.四 抽象被观察者 Subject

public interface Subject {public void registerObserver(Observer observer);public void remove (Observer observer);public void notifyObservers();
}

二.五 具体观察者实现

@Slf4j
public class WeatherDataSubject implements Subject{private List<Observer> observerList = new ArrayList<>();private Weather weather;@Overridepublic void registerObserver(Observer observer) {observerList.add(observer);}@Overridepublic void remove(Observer observer) {observerList.remove(observer);}@Overridepublic void notifyObservers() {for (Observer observer : observerList) {observer.update(this.weather);}}public void setWeather(Weather weather) {this.weather = weather;dataChange();}public void dataChange() {// 更新后,数据发生了改变。log.info("获取到了最新的数据: {}", this.weather);notifyObservers();}
}

二.六 客户端调用

  @Testpublic void oneTest() {WeatherDataSubject weatherDataSubject = new WeatherDataSubject();weatherDataSubject.registerObserver(new BaiDu());weatherDataSubject.registerObserver(new Sina());// 设置数据weatherDataSubject.setWeather(Weather.builder().temperature(35.0f).pressure(20.0f).humidity(30.f).build());User user = new User();// 再添加个数据weatherDataSubject.registerObserver(user);weatherDataSubject.setWeather(Weather.builder().temperature(30.0f).pressure(21.0f).humidity(32.f).build());weatherDataSubject.remove(user);weatherDataSubject.setWeather(Weather.builder().temperature(32.0f).pressure(22.0f).humidity(33.f).build());}

image-20230615185146367

三. Java 实现观察者模式

Java 语言, 可以通过 Observer(Observer) Observable(Subject) 实现观察者处理

三.一 具体观察者和抽象观察者

@Slf4j
public class NewUser implements Observer {private String name;public NewUser(String name) {this.name = name;}@Overridepublic void update(Observable o, Object arg) {log.info("{} 观察到信息发生了变化 {}", name,arg);}
}

三.二 具体被观察者和抽象被观察者

public class NewWeatherDataSubject extends Observable {private Weather weather;public NewWeatherDataSubject (Weather weather) {this.weather = weather;}public void setWeather(Weather weather) {this.weather = weather;// 改变了super.setChanged();super.notifyObservers(weather);}
}

三.三 客户端调用

@Testpublic void twoTest() {Weather weather = Weather.builder().temperature(32.0f).pressure(22.0f).humidity(33.f).build();NewWeatherDataSubject newWeatherDataSubject = new NewWeatherDataSubject(weather);newWeatherDataSubject.addObserver(new NewUser("用户1"));newWeatherDataSubject.addObserver(new NewUser("用户2"));newWeatherDataSubject.addObserver(new NewUser("用户3"));log.info("温度发生改变");weather.setTemperature(34.f);newWeatherDataSubject.setWeather(weather);log.info("温度再次发生改变");weather.setTemperature(30.f);newWeatherDataSubject.setWeather(weather);}

image-20230615185508442


本章节的代码放置在 github 上:


https://github.com/yuejianli/DesignPattern/tree/develop/Observer


谢谢您的观看,如果喜欢,请关注我,再次感谢 !!!


http://www.ppmy.cn/news/404393.html

相关文章

联想小新电脑摄像头打不开

如下图 排除了顶部物理键阻挡以及未开摄像头权限后&#xff0c;发现是在联想电脑管家开启了隐私模式&#xff0c;如下图。

联想小新m7208w扫描仪原理的文档给我一份

抱歉&#xff0c;我不能给您提供联想小新m7208w扫描仪原理的文档。但是&#xff0c;您可以在联想官网或者第三方网站上搜索该产品的说明书或技术资料。

联想笔记本小新V2000怎么进BIOS设置

进入主板BIOS一般是启动时按Del、ESC、F2等按键&#xff0c;一些新型的笔记本则采用专用的高级启动按键&#xff0c;比如联想小新v2000笔记本就有一键恢复高级按钮&#xff0c;接下来系统城小编就跟大家分享联想v2000怎么进入BIOS界面以及BIOS各项设置菜单的介绍。 操作步骤如下…

联想小新一体机扫描头原理

联想小新一体机扫描头是通过光学原理来实现扫描图像的。它通过一个移动的光源和一个静止的接收器来捕捉图像。光源照射到物体上&#xff0c;反射回来的光线被接收器捕捉&#xff0c;然后通过电子元件转换成数字信号&#xff0c;最终被计算机识别为图像。

SQL高级之其他优化项

分页查询优化 limit优化 条件 order by 后的字段&#xff08;XXX&#xff09;有索引sql 中有 limit 时 结果 当 select id 或 XXX字段索引包含字段时 &#xff0c;显示 using index当 select 后的字段含有 order by 字段索引不包含的字段时&#xff0c;将显示 using filesor…

驾驶安全、便捷,尽在车载Notification开发的掌握

Notification 概述 通知&#xff08;Notification&#xff09;是移动应用中常用的一种交互方式&#xff0c;用于向用户展示重要的信息、提醒事件或提供即时反馈等。通知可以以弹出窗口、图标或声音等形式呈现给用户。 以下是关于通知的一些基本概念和要点&#xff1a; 通知栏…

正则表达式笔记

/你的正则表达式写在这里/ 1? 1出现0次或1次 1* 1出现0次或多次 1 1出现1次或多次 1{2} 1出现了2次 1{2,3} 1出现了2到3次 1{2,} 1出现了2次及以上 (5555){1} 5555出现了1次 (dog|cat) dog或者cat [a-zA-Z] a…

代码随想录二叉树 Java(三)

文章目录 &#xff08;简单&#xff09;501. 二叉搜索树中的众数&#xff08;*中等&#xff09;236. 二叉树的最近公共祖先&#xff08;中等&#xff09;235. 二叉搜索树的最近公共祖先&#xff08;中等&#xff09;701. 二叉搜索树中的插入操作&#xff08;*中等&#xff09;4…