设计模式 -- 观察者模式(Observer Pattern)

news2024/12/24 2:17:37

1 问题引出

1.1 天气预报项目需求

  1. 气象站可以将每天测量到的温度,湿度,气压等等以公告的形式发布出去(比如发布到自己的网站或第三方)。

  2. 需要设计开放型 API,便于其他第三方也能接入气象站获取数据。

  3. 提供温度、气压和湿度的接口

  4. 测量数据更新时,要能实时的通知给第三方

1.2 传统的设计方案

说明:

  1. 通过 getxxx() 方法,可以让第三方接入,并得到相关信息.
  2. 当数据有更新时,气象站通过调用 dataChange() 去更新数据,当第三方再次获取时,就能得到最新数据,当然也可以推送。
  3. Currentconditions(当前的天气情况) 可以理解成是我们气象局的网站

3 组件和结构

  1. 主题(Subject):又称被观察者或可观察对象。它是具有状态的对象,并维护一个观察者列表。主题提供了添加、删除和通知观察者的方法。
  2. 观察者(Observer):是接收主题通知的对象。每一个观察者都需要实现一个更新接口,以便在收到主题通知时进行相应的操作。
  3. 具体主题(ConcreteSubject):具体实现了主题接口,管理观察者列表,并在状态改变时通知它们。
  4. 具体观察者(ConcreteObserver):实现了观察者接口的具体类,定义了在收到主题通知时需要执行的具体操作。

4 应用实例

4.1实现原理

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

  1. registerObserver 注册

  2. removeObserver 移除

  3. notifyObservers() 通知所有的注册的用户,根据不同需求,可以是更新数据,让用户来取,也可能是实施推送, 看具体需求定

Ø Observer:接收输入

4.2 类图

4.3 代码实现

Client

public class Client {
​
    public static void main(String[] args) {
        //  创建一个 WeatherData
        WeatherData weatherData = new WeatherData();
​
        //  创建观察者
        CurrentConditions currentConditions = new CurrentConditions();
​
        BaiduSite baiduSite = new BaiduSite();
​
        //  注册到 weatherData 
        weatherData.registerObserver(currentConditions);
        weatherData.registerObserver(baiduSite);
​
        //  测试
        System.out.println("通知各个注册的观察者, 看看信息");
        weatherData.setData(10f, 100f, 30.3f);
​
        weatherData.removeObserver(currentConditions);
        //  测试System.out.println();
        System.out.println("通知各个注册的观察者, 看看信息");
        weatherData.setData(10f, 100f, 30.3f);
    }
​
}

BaiduSite

public class BaiduSite implements Observer {
​
    //  温度,气压,湿度
    private float temperature;
    private float pressure;
​
    private float humidity;
​
    //  更新 天气情况,是由 WeatherData 来调用,我使用推送模式
    public void update(float temperature, float pressure, float humidity) {
        this.temperature = temperature;
​
        this.pressure = pressure;
        this.humidity = humidity;
        display();
    }
​
    //  显示
    public void display() {
        System.out.println("===百度网站====");
        System.out.println("***百度网站 气温 : " + temperature + "***");
        System.out.println("***百度网站 气压: " + pressure + "***");
        System.out.println("***百度网站 湿度: " + humidity + "***");
    }
​
}

Observer

public interface Observer {
    public void update(float temperature, float pressure, float humidity);
}

Subject

// 接口, 让 WeatherData 来实现
public interface Subject {
    public void registerObserver(Observer o); 
    public void removeObserver(Observer o); 
    public void notifyObservers();
}

WeatherData


/**
 * 类是核心
 * 1. 包含最新的天气情况信息
 * 2. 含有 观察者集合,使用 ArrayList 管理
 * 3. 当数据有更新时,就主动的调用 ArrayList, 通知所有的(接入方)就看到最新的信息
 */
public class WeatherData implements Subject {
    private float temperatrue;
    private float pressure;
​
    private float humidity;
    //  观察者集合
    private ArrayList<Observer> observers;
​
    //  加入新的第三方
    public WeatherData() {
        observers = new ArrayList<Observer>();
    }
​
    public float getTemperature() {
        return temperatrue;
    }
​
    public float getPressure() {
        return pressure;
    }
​
    public float getHumidity() {
        return humidity;
    }
​
    public void dataChange() {
        //  调用 接入方的 update
        notifyObservers();
    }
​
    //  当数据有更新时,就调用 setData
    public void setData(float temperature, float pressure, float humidity) {
        this.temperatrue = temperature;
        this.pressure = pressure;
        this.humidity = humidity;
        //  调用 dataChange, 将最新的信息 推送给 接入方 currentConditions
        dataChange();
    }
​
    //  注册一个观察者@Override
    public void registerObserver(Observer o) {
        observers.add(o);
    }
​
    //  移除一个观察者@Override
    public void removeObserver(Observer o) {
        if(observers.contains(o)) {
        observers.remove(o);
    }
        
    //  遍历所有的观察者,并通知
    @Override
    public void notifyObservers() {
        for (int i = 0; i < observers.size(); i++) {
            observers.get(i)
                .update(this.temperatrue, this.pressure, this.humidity);
        }
    }
}

5 优缺点

5.1 优点

  1. 支持松耦合:观察者模式允许主题和观察者独立变化,只要他们之间的通信遵守约定的接口,变化不会相互影响。这样,我们增加观察者(这里可以理解成一个新的公告板),就不需要去修改核心类 WeatherData 不会修改代码, 遵守了 ocp 原则。
  2. 动态订阅:观察者可以动态地订阅或取消订阅主题,这意味着可以在运行时改变通知的对象集,提供了高度的灵活性。
  3. 支持广播通信:当主题状态改变时,所有注册的观察者都会收到通知,这大大简化了一对多的消息传递机制。
  4. 能力集中:观察者模式设计后,会以集合的方式来管理用户(Observer),包括注册,移除和通知。

5.2 缺点

  1. 性能问题:如果观察者数量众多,通知过程可能会耗费较长时间,影响性能。
  2. 循环依赖问题:如果观察者和主题之间存在循环依赖,可能导致系统崩溃。
  3. 信息不足:观察者可能只能知道主题发生了变化,但无法获取更多关于变化细节的信息。

6 应用场景

  1. GUI事件处理:在图形用户界面编程中,各种控件(如按钮、滑块等)可以被视为主题,而响应用户交互的动作(如点击、移动等)则由观察者(如事件处理器)来处理。
  2. 数据同步:当数据在一端发生变化时,可以使用观察者模式自动更新所有依赖于此数据的对象。
  3. 实时系统:在实时系统中,多个对象可能需要对某个对象的状态变化做出响应,观察者模式提供了一个高效的框架来实现这一点。

7 总结

        观察者模式是解决对象间一对多依赖关系的强大工具,通过状态改变的通知机制,它使得系统更加灵活和动态。然而,设计时也要注意其潜在的性能问题和循环依赖的问题。正确应用观察者模式,可以使你的系统更加模块化和易于扩展。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2103429.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C语言指针进阶二:(函数指针数组,转移表)

函数指针数组 函数指针数组就是存放函数指针的一个数组&#xff0c;数组里都是函数指针&#xff0c;那么该怎么定义: int (*parr[10])(); 因为 [] 的优先级高于 * &#xff0c;所以parr先与 [] 结合说明是一个数组&#xff0c;元素类型是 int(*)() 的函数指针。 函数指针…

Tool-SQL:基于Agent智能体的Text2SQL解决方案,显著提升Text2SQL效果

Tool-SQL&#xff1a;基于Agent智能体的Text2SQL解决方案&#xff0c;显著提升Text2SQL效果 近期&#xff0c;Text-to-SQL 技术通过整合数据库系统的反馈&#xff0c;有效利用了大型语言模型&#xff08;LLMs&#xff09;。尽管这些技术能有效纠正 SQL 查询的执行错误&#xff…

计算机工具软件安装攻略:Visual Studio Code下载

Visual Studio Code下载、安装和使用 1 Visual Studio Code简介 Visual Studio Code通常简称为VS Code&#xff0c;是一款由微软开发的免费、开源的轻量级代码编辑器。它在开发者社区中非常受欢迎&#xff0c;具有强大的功能和扩展性&#xff0c;适用于多种编程语言和开发场景…

文章解读与仿真程序复现思路——中国电机工程学报EI\CSCD\北大核心《考虑极端事件的电力系统惯量与一次调频备用联合规划配置方法》

本专栏栏目提供文章与程序复现思路&#xff0c;具体已有的论文与论文源程序可翻阅本博主免费的专栏栏目《论文与完整程序》 论文与完整源程序_电网论文源程序的博客-CSDN博客https://blog.csdn.net/liang674027206/category_12531414.html 电网论文源程序-CSDN博客电网论文源…

统计学习与方法实战——统计学习方法概论

统计学习方法概论题 统计学习方法概论实现统计学习方法的步骤统计学习方法三要素模型策略损失函数与风险函数定义 常用损失函数经验风险最小化(ERM)与结构风险最小化(SRM) 模型评估与模型选择过拟合与模型选择 正则化与交叉验证泛化能力生成模型与判别模型生成方法判别方法 最小…

制定精益生产现场管理和改善计划时,企业需要考虑哪些因素

在制定精益生产现场管理与改善计划时&#xff0c;企业需综合考虑多个维度&#xff0c;以确保计划既能高效实施&#xff0c;又能持续推动生产流程的优化与效率提升。以下是深圳天行健企业管理咨询公司对这一过程中需重点考虑因素的详细阐述&#xff1a; 一、企业现状 1. 生产流…

Datawhale X李宏毅苹果书进阶 AI夏今营 task03学习笔记

batch normalization(批次标准化&#xff09; batch normalization--Tarining 直接改error surface的landscape&#xff0c;把山“铲平”有时候尽管error surface是个“碗”&#xff0c;都不见得好train。如下图所示&#xff1a; w1,w2对loss的斜率差别很大&#xff0c;w1方…

解锁SQL无限可能 | 利用SQL实现13位条码检测算法

目录 0 需求分析 1 数据准备 2 问题分析 3 小结 数字化建设通关指南专栏原价99&#xff0c;现在活动价39.9&#xff0c;按照阶梯式增长&#xff0c;直到恢复原价 0 需求分析 算法&#xff1a;给定一个n位的数字字符串&#xff0c;取出这个条码字符串的前n-1位数字&…

Elasticsearch数据写入过程

1. 写入请求 当一个写入请求&#xff08;如 Index、Update 或 Delete 请求&#xff09;通过REST API发送到Elasticsearch时&#xff0c;通常包含一个文档的内容&#xff0c;以及该文档的索引和ID。 2. 请求路由 协调节点&#xff1a;首先&#xff0c;请求会到达一个协调节点…

Linux:目录及文件管理

目录及文件管理 cd的命令使用 . 当前目录 .. 父目录&#xff08;上一层&#xff09; ~ 表示家目录 家目录&#xff1a;专门存放用户个性化信息的目录 ~user&#xff1a;用户user的家目录 /root: 是Linux管理员的家目录 /home: 存放所有普通用户的家目录]# cd ~root #去…

Leetcode面试经典150题-106.从中序和后序序列构造二叉树

解法都在代码里&#xff0c;不懂就留言或者私信 /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode() {}* TreeNode(int val) { this.val val; }* TreeNode(int val, TreeNo…

作为HR如何解决薪资谈判的僵局

作为HR如何跟候选人谈薪资问题&#xff0c;特别候选人的期望值&#xff0c;和公司对岗位的设定范围存在不对等的情况下&#xff0c;HR和候选人的薪资谈判往往就陷入僵局。面对这种情况&#xff0c;是直接放弃&#xff0c;还是有努力的空间呢&#xff1f; 在面对薪资谈判僵局时…

基于tesseract实现文档OCR识别

导入环境 导入必要的库 numpy: 用于处理数值计算。 argparse: 用于处理命令行参数。 cv2: OpenCV库&#xff0c;用于图像处理。 import numpy as np import argparse import cv2设置命令行参数 ap argparse.ArgumentParser() ap.add_argument("-i", "--imag…

中国各省份-环境规制相关数据(2000-2022年)

环境规制&#xff0c;也称为环保政策和污染治理&#xff0c;是一系列由政府制定的旨在解决环境问题、保护生态环境和促进可持续发展的政策措施。这些措施包括法律法规、行政命令、经济激励和市场机制等&#xff0c;目的是约束和指导企业和个人行为&#xff0c;减少对环境的负面…

【吊打面试官系列-Redis面试题】Redis 的同步机制了解么?

大家好&#xff0c;我是锋哥。今天分享关于 【Redis 的同步机制了解么&#xff1f;】面试题&#xff0c;希望对大家有帮助&#xff1b; Redis 的同步机制了解么&#xff1f; 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 Redis 可以使用主从同步&#xff0c;从从同…

Linux运维--iptables防火墙命令以及端口号等详解(全)

Linux之iptable防火墙命令以及端口号等详解&#xff08;全&#xff09; 在Linux系统中&#xff0c;你可以使用firewalld和iptables来管理和设置防火墙规则。Firewalld是一个动态管理防火墙的工具&#xff0c;而iptables是一个更底层的工具&#xff0c;可以直接配置Linux内核的…

经典卷积神经网络 (CNN) 架构模型详解:LeNet、AlexNNet、GoogleNet、ResNet、DenseNet

《博主简介》 小伙伴们好&#xff0c;我是阿旭。专注于人工智能、AIGC、python、计算机视觉相关分享研究。 &#x1f44d;感谢小伙伴们点赞、关注&#xff01; 《------往期经典推荐------》 一、AI应用软件开发实战专栏【链接】 项目名称项目名称1.【人脸识别与管理系统开发…

文字转视频软件哪个好用?揭秘创意新工具

最近&#xff0c;我在筹备一个小型的个人项目&#xff0c;需要制作一系列的教学视频&#xff0c;但我对视频编辑一窍不通。就在我快要放弃的时候&#xff0c;我发现了一些神奇的工具&#xff0c;它们能自动把文字变成视频&#xff01; 想知道自动生成视频的软件有哪些吗&#…

Docker 安装FileBeat、Elasticsearch及Kibana详细步骤

一、ELK简介 二、docker安装Elasticsearch 2.1 创建Docker网络 2.2 拉取镜像 2.3 创建挂载目录 2.4 添加配置文件 2.5 创建es容器 2.6 测试Elasticsearch是否安装成功 三、docker安装Logstash 3.1 拉取镜像 3.2 创建挂载目录 3.3 添加配置文件 3.4 创建Logstash容…

如何更新我的SSL证书到期日期?

续订SSL证书需要获取新证书来替换即将过期的证书。该过程可能略有不同&#xff0c;具体取决于Gworg获取证书的方法。以下是有关如何续订SSL证书的一般指南&#xff1a; 检查有效期&#xff1a; 在开始续订流程之前&#xff0c;请检查SSL证书的当前到期日期。您通常可以在SSL证…