首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐

设计模式 —— 观察者模式

  • 25-03-07 20:22
  • 3019
  • 10374
blog.csdn.net

先来认识一下观察者模式

观察者模式(Observer),又叫发布-订阅模式(Publish/Subscribe),定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并自动更新。

 

一、观察者模式项目需求

天气预报项目需求,具体要求如下:

  1. 气象站可以将每天测量到的温度,湿度,气压等等以公告的形式发布出去(比如发布到自己的网站或第三方)
  2. 需要设计开放型 API,便于其他第三方也能接入气象站获取数据
  3. 提供温度、气压和湿度的接口
  4. 测量数据更新时,要能实时的通知给第三方

 

1.1 天气预报设计方案 1-普通方案

  1. WeatherData 类
  2. 传统的设计方案

普通方案代码示例:

  1. /**
  2. 显示当前天气情况(可以理解成是气象站自己的网站)
  3. */
  4. public class CurrentConditions {
  5. // 温度,气压,湿度
  6. private float temperature;
  7. private float pressure;
  8. private float humidity;
  9. // 更新天气情况,是由WeatherData 来调用,使用推送模式
  10. public void update(float temperature, float pressure, float humidity) {
  11. this.temperature = temperature;
  12. this.pressure = pressure;
  13. this.humidity = humidity;
  14. display();
  15. }
  16. // 显示
  17. public void display() {
  18. System.out.println("***Today mTemperature: " + temperature + "****");
  19. System.out.println("***Today mPressure: " + pressure + "****");
  20. System.out.println("***Today mHumidity: " + humidity + "****");
  21. }
  22. }
  1. /**
  2. * 类是核心
  3. * 1、包含最新的天气情况信息
  4. * 2、含有 CurrentConditions 对象
  5. * 3、当数据有更新时,就主动的调用 CurrentConditions 对象update方法(含display),这样他们(接入方)就看到最新的信息
  6. */
  7. public class WeatherData {
  8. // 温度,气压,湿度
  9. private float temperature;
  10. private float pressure;
  11. private float humidity;
  12. private CurrentConditions currentConditions;
  13. public WeatherData(CurrentConditions currentConditions) {
  14. this.currentConditions = currentConditions;
  15. }
  16. public float getTemperature() {
  17. return temperature;
  18. }
  19. public float getPressure() {
  20. return pressure;
  21. }
  22. public float getHumidity() {
  23. return humidity;
  24. }
  25. public void dataChange() {
  26. // 调用 接入方的 update
  27. currentConditions.update(getTemperature(), getPressure(), getHumidity());
  28. }
  29. // 当数据有更新时,就调用setData
  30. public void setData(float temperature, float pressure, float humidity) {
  31. this.temperature = temperature;
  32. this.pressure = pressure;
  33. this.humidity = humidity;
  34. // 调用dataChange,将最新的信息,推送给接入方 currentConditions
  35. dataChange();
  36. }
  37. }
  1. public class Client {
  2. public static void main(String[] args) {
  3. // 创建接入方 currentConditions
  4. CurrentConditions currentConditions = new CurrentConditions();
  5. // 创建 WeatherData 并将接入方 currentConditions 传递到WeatherData中
  6. WeatherData weatherData = new WeatherData(currentConditions);
  7. // 更新天气情况
  8. weatherData.setData(30, 150, 40);
  9. // 天气情况变化
  10. System.out.println("========== 天气情况变化 ==========");
  11. weatherData.setData(40, 160, 20);
  12. }
  13. }

1.2 普通方案问题分析

  1. 其他第三方接入气象站获取数据的问题
  2. 无法在运行时动态的添加第三方接入者 (新浪网站)
  3. 违反 ocp 原则

在 WeatherData 中,当增加一个第三方,都需要创建一个对应的第三方的公告板对象,并加入到dataChange,不利于维护,也不是动态加入

  1. public void dataChange() {
  2. currentConditions.update(getTemperature(), getPressure(), getHumidity());
  3. }

二、观察者模式原理

  1. 观察者模式类似订牛奶业务
  2. 奶站 / 气象局:Subject
  3. 客户 / 第三方网站:Observer

Subject:登记注册、移除和通知

  1. registerObserver 注 册
  2. removeObserver 移 除
  3. notifyObservers() 通知所有的注册的用户,根据不同需求,可以是更新数据,让用户来取,也可能是实施推送

Observer:接收输入

观察者模式:对象之间多对一依赖的一种设计方案,被依赖的对象为 Subject,依赖的对象为Observer,Subject

通知 Observer 变化,比如这里的奶站是 Subject,是 1 的一方。用户时 Observer,是多的一方

 

2.1 观察者模式解决天气预报需求

类图说明

观察者模式方案:

  1. // 观察者接口,由观察者来实现
  2. public interface Observer {
  3. public void update(float temperature, float pressure, float humidity);
  4. }
  1. // 接口,让WeatherData 来实现
  2. public interface Subject {
  3. public void registerObserver(Observer o);
  4. public void removeObserver(Observer o);
  5. public void notifyObservers();
  6. }
  1. /**
  2. 显示当前天气情况(可以理解成是气象站自己的网站)
  3. */
  4. public class CurrentConditions implements Observer {
  5. // 温度,气压,湿度
  6. private float temperature;
  7. private float pressure;
  8. private float humidity;
  9. // 更新天气情况,是由WeatherData 来调用,使用推送模式
  10. public void update(float temperature, float pressure, float humidity) {
  11. this.temperature = temperature;
  12. this.pressure = pressure;
  13. this.humidity = humidity;
  14. display();
  15. }
  16. // 显示
  17. public void display() {
  18. System.out.println("***Today mTemperature: " + temperature + "****");
  19. System.out.println("***Today mPressure: " + pressure + "****");
  20. System.out.println("***Today mHumidity: " + humidity + "****");
  21. }
  22. }
  1. public class BaiduSite implements Observer {
  2. // 温度,气压,湿度
  3. private float temperature;
  4. private float pressure;
  5. private float humidity;
  6. // 更新天气情况,是由WeatherData 来调用,使用推送模式
  7. public void update(float temperature, float pressure, float humidity) {
  8. this.temperature = temperature;
  9. this.pressure = pressure;
  10. this.humidity = humidity;
  11. display();
  12. }
  13. // 显示
  14. public void display() {
  15. System.out.println("========百度网站============");
  16. System.out.println("*** 百度网站 mTemperature: " + temperature + "****");
  17. System.out.println("*** 百度网站 mPressure: " + pressure + "****");
  18. System.out.println("*** 百度网站 mHumidity: " + humidity + "****");
  19. }
  20. }
  1. /**
  2. * 类是核心
  3. * 1、包含最新的天气情况信息
  4. * 2、含有 观察者集扣,使用ArrayList管理
  5. * 3、当数据有更新时,就主动的调用 ArrayList,通知所有的(接入方)就看到最新的信息
  6. */
  7. public class WeatherData implements Subject {
  8. // 温度,气压,湿度
  9. private float temperature;
  10. private float pressure;
  11. private float humidity;
  12. // 观察者集合
  13. private ArrayList observers;
  14. public WeatherData() {
  15. observers = new ArrayList<>();
  16. }
  17. public float getTemperature() {
  18. return temperature;
  19. }
  20. public float getPressure() {
  21. return pressure;
  22. }
  23. public float getHumidity() {
  24. return humidity;
  25. }
  26. public void dataChange() {
  27. // 调用 接入方的 update
  28. //currentConditions.update(getTemperature(), getPressure(), getHumidity());
  29. notifyObservers();
  30. }
  31. // 当数据有更新时,就调用setData
  32. public void setData(float temperature, float pressure, float humidity) {
  33. this.temperature = temperature;
  34. this.pressure = pressure;
  35. this.humidity = humidity;
  36. // 调用dataChange,将最新的信息,推送给接入方 currentConditions
  37. dataChange();
  38. }
  39. // 注册一个观察者
  40. @Override
  41. public void registerObserver(Observer o) {
  42. observers.add(o);
  43. }
  44. // 移除一个观察者
  45. @Override
  46. public void removeObserver(Observer o) {
  47. observers.remove(o);
  48. }
  49. // 遍历所有的观察者,并通知
  50. @Override
  51. public void notifyObservers() {
  52. for (int i = 0; i < observers.size(); i++) {
  53. observers.get(i).update(this.temperature, this.pressure, this.humidity);
  54. }
  55. }
  56. }
  1. public class Client {
  2. public static void main(String[] args) {
  3. // 创建一个WeatherData
  4. WeatherData weatherData = new WeatherData();
  5. // 创建观察者
  6. CurrentConditions currentConditions = new CurrentConditions();
  7. // 注册到weatherData
  8. weatherData.registerObserver(currentConditions);
  9. weatherData.registerObserver(new BaiduSite());
  10. weatherData.removeObserver(currentConditions);
  11. // 测试
  12. System.out.println("通知各个注册的观察者,看看信息");
  13. weatherData.setData(10, 100, 30.3f);
  14. }
  15. }

 

 

2.2 观察者模式的好处

  1. 观察者模式设计后,会以集合的方式来管理观察乾 (Observer),包括注册,移除和通知
  2. 这样,我们增加观察者 (这里可以理解成一个新的客户接入进来),就不需要去修改核心业务类 WeatherData 不会修改代码, 遵守了 ocp 原则

 


三、观察者模式在 Jdk 应用的源码分析

  1. Jdk 的 Observable 类就使用了观察者模式
  2. 代码分析+模式角色分析

模式角色分析

  • Observable 的作用和地位等价于 我们前面讲过 Subject
  • Observable 是类,不是接口,类中已经实现了核心的方法,即管理 Observer 的方法 add.. delete .. notify...
  • Observer 的作用和地位等价于我们前面讲过的 Observer,有 update
  • Observable 和 Observer 的使用方法和前面讲过的一样,只是 Observable 是类,通过继承来实现观察者模式

四、分析观察者模式

4.1 观察者模式的主要优点

  • 观察者和被观察者是抽象耦合的
  • 建立了一套触发机制

4.2 观察者模式的缺点

  • 如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间
  • 如果观察者和观察目标间有循环依赖,可能导致系统崩溃
  • 没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的

4.3 观察者模式的使用场景

  • 关联行为场景
  • 事件多级触发场景
  • 跨系统的消息变换场景,如消息队列的处理机制

4.4 观察者模式应用实例

  • 手机丢了,委托别人给其他人发消息通知
  • 通知老师/老板来了
  • 拍卖,拍卖师观察最高标价,然后通知给其它竞价者竞价
  • 在一个目录下建立一个文件,会同时通知目录管理器增加目录,并通知磁盘减少空间,文件是被观察者,目录管理器和磁盘管理器是观察者
  • 猫叫了一声,吓着了老鼠,也惊到了主人,猫是被观察者,老鼠和人是观察者

4.5 观察者模式使用注意事项

  • 避免循环引用
  • 如果顺序执行,某一观察者错误会导致系统卡壳,一般采用异步方式

 

当一个对象的改变需要同时改变其它对象,并且它不知道具体有多少对象有待改变的时候,应该考虑使用观察者模式。

  而使用观察者模式的动机在于:将一个系统分割成一系列相互协作的类有一个很不好的副作用,就是需要维护相关对象间的一致性,我们不希望为了维持一致性而使各类紧密耦合,这样会给维护、扩展和重用都带来不便,而观察者模式所做的工作就是在解除耦合。

 


文章最后,给大家推荐一些受欢迎的技术博客链接:

  1. JAVA相关的深度技术博客链接
  2. Flink 相关技术博客链接
  3. Spark 核心技术链接
  4. 设计模式 —— 深度技术博客链接
  5. 机器学习 —— 深度技术博客链接
  6. Hadoop相关技术博客链接
  7. 超全干货--Flink思维导图,花了3周左右编写、校对
  8. 深入JAVA 的JVM核心原理解决线上各种故障【附案例】
  9. 请谈谈你对volatile的理解?--最近小李子与面试官的一场“硬核较量”
  10. 聊聊RPC通信,经常被问到的一道面试题。源码+笔记,包懂
  11. 深入聊聊Java 垃圾回收机制【附原理图及调优方法】

欢迎扫描下方的二维码或 搜索 公众号“大数据高级架构师”,我们会有更多、且及时的资料推送给您,欢迎多多交流!

                                           

       

 

注:本文转载自blog.csdn.net的不埋雷的探长的文章"https://blog.csdn.net/weixin_32265569/article/details/108415408"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2492) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

101
推荐
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2025 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top