技术成神之路:设计模式(九)观察者模式

news2024/11/11 8:02:23

介绍

观察者模式(Observer Pattern)是一种行为设计模式。它允许一个对象(称为主题或可观察者)来监视并通知一组依赖于这个对象的其他对象(称为观察者),以便在主题状态发生变化时自动更新观察者的对象。

1.定义


观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态变化时,会通知所有注册过的观察者对象,使它们能够自动更新自己。

2.主要作用


主要作用是解耦主题与观察者之间的耦合关系,使得主题和观察者之间可以轻松地进行交互和通信。

3.解决的问题


  • 对象间的依赖关系管理:将对象间的依赖关系从静态写死的调用关系解耦,通过抽象出观察者接口和主题接口来管理对象间的关系。

  • 通知机制:当一个对象的状态发生变化时,需要通知其他相关的对象做出相应的改变,观察者模式提供了一种灵活的通知机制。

观察者模式应该是我们在开发中使用最频繁的一个设计模式了,比如在安卓中经常用到的:

  1. LiveData 和 Observer:LiveData 是一种在 Android 应用中生命周期感知的可观察数据持有类。可以存储数据,并在数据发生变化时通知其观察者。通常与 Observer 结合使用。
  2. BroadcastReceiver 和 IntentFilter:广播发送者和接收者之间的通信机制可以看作是一种观察者模式的实现。
  3. RxJava 和 Observer:提供了 Observables 和 Observers 的概念,可以用来实现观察者模式。

注意 观察者模式的定义是一对多的关系,像监听事件只能算回调(Callback),不严格符合传统的观察者模式的定义!

4.模式原理


包含角色:

  • Subject(主题):维护一组观察者对象,提供注册和删除观察者对象的接口。主题对象状态发生变化时,调用观察者的相应方法。

  • Observer(观察者):定义一个更新接口,使得在主题对象状态改变时能够得到通知和更新。

  • ConcreteSubject(具体主题):将有关状态存入具体观察者对象;在具体主题的内部状态改变时,给所有登记过的观察者发出通知。

  • ConcreteObserver(具体观察者):维护一个指向具体主题对象的引用,存储与主题的状态相对应的信息。实现 Observer 定义的更新接口,以便使自身状态与主题的状态保持一致。

UML类图:
在这里插入图片描述
示例代码:

主题接口 Subject

import java.util.ArrayList;
import java.util.List;

// 主题接口
interface Subject {
    void registerObserver(Observer observer);
    void removeObserver(Observer observer);
    void notifyObservers();
}

// 具体主题类
class ConcreteSubject implements Subject {
    private List<Observer> observers = new ArrayList<>();
    private int state;

    public int getState() {
        return state;
    }

    public void setState(int state) {
        this.state = state;
        notifyObservers();
    }

    @Override
    public void registerObserver(Observer observer) {
        observers.add(observer);
    }

    @Override
    public void removeObserver(Observer observer) {
        observers.remove(observer);
    }

    @Override
    public void notifyObservers() {
        for (Observer observer : observers) {
            observer.update(state);
        }
    }
}

观察者接口 Observer

// 观察者接口
interface Observer {
    void update(int state);
}

// 具体观察者类
class ConcreteObserver implements Observer {
    private int observerState;

    @Override
    public void update(int state) {
        observerState = state;
        System.out.println("Observer state updated: " + observerState);
    }
}

使用

public class ObserverPatternExample {
    public static void main(String[] args) {
        // 创建具体主题对象
        ConcreteSubject subject = new ConcreteSubject();

        // 创建具体观察者对象
        ConcreteObserver observer1 = new ConcreteObserver();
        ConcreteObserver observer2 = new ConcreteObserver();

        // 注册观察者
        subject.registerObserver(observer1);
        subject.registerObserver(observer2);

        // 改变主题状态,并触发通知
        subject.setState(10);

        // 移除一个观察者
        subject.removeObserver(observer1);

        // 再次改变主题状态,并触发通知
        subject.setState(20);
    }
}

打印

Observer state updated: 10
Observer state updated: 10

Observer state updated: 20

上面举例为标准的观察者模式写法,我记得在上家公司代码中 有一种奇怪的写法,当然,也符合观察者模式定义。

在安卓中不同组件之间大多都有传递消息的需求,大家常用的库有EventBus吧。简单,方便,它是定义了一个 IHandler类,其中代码 就像上面 ConcreteSubject 类中差不多,只不过多了一个Handler 就是为了方便切换线程的,保证观察者收到的消息都是在主线程中,注意他是一个类,不是接口,而且所有代码都在IHandler 类中,谁继承它 就是 具体主题类 ,因为安卓是单继承嘛,这个使用起来很不方便。

无论你在任何地方,想要得到这个 具体主题类的消息,只需要向它注册观察者即可,当然最后别忘了反注册,不然要内存泄漏了,刚用的时候稍不留意就忘了,可恶心,当然 这个具体主题类 一般都是单例,全局唯一对象,因为当时是霸屏应用(特殊场景),所以单例满天飞,用的时候可爽,哈哈哈,现在回想起来都是问题。

5.优缺点


优点:

  • 解耦性:主题和观察者之间是抽象耦合,容易扩展。
  • 支持广播通信:主题可以通知多个观察者,观察者也可以接收多个主题的通知。
  • 灵活性:可以动态地设置通知方式和观察者的添加和删除。

缺点:

  • 可能引起循环调用:如果观察者和主题之间的依赖关系设计不当,可能导致循环调用。
  • 通知效率:如果通知过于频繁,可能会影响系统性能,一般场景这个问题不用考虑的,但如果你的观察者好多个甚至几十上百的话 就不得不考虑效率问题了。

6.应用场景


  1. 当一个抽象模型有两个方面,其中一个依赖于另一个。
  2. 当一个对象的改变需要同时改变其他对象,而不知道具体有多少对象需要改变时。
  3. 当一个对象必须通知其他对象,而它又不能假定其他对象是谁。

7.总结


观察者模式通过定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象,实现了对象之间的解耦和通信。它是实现事件驱动程序设计的基础,广泛应用于GUI(Graphical User Interface,图形用户界面)开发、事件处理系统等需要高内聚、低耦合的场景中。

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

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

相关文章

python机器学习8--自然语言处理(1)

1.基本定义&#xff1a; 语义&#xff1a;就是一句话的重点是什么。 自定词汇&#xff1a;因为语言、文字太多&#xff0c;自定和处理你所关心的重点词汇。 简体转繁体代码 from opencc import OpenCCtext1 "我去过清华大学" openCC OpenCC(s2t) line openCC.…

【系统架构设计师】计算机组成与体系结构 ⑯ ( 奇偶校验码 | CRC 循环冗余码 | 海明码 | 模 2 除法 )

文章目录 一、校验码1、校验码由来2、奇偶校验码3、CRC 循环冗余码 ( 重点考点 )4、海明码校验 ( 软考不经常考到 ) 二、CRC 循环冗余码 ( 重点考点 )1、模 2 除法概念2、模 2 除法步骤3、模 2 除法示例4、CRC 循环冗余码示例 15、CRC 循环冗余码示例 2 参考之前的博客 : 【计…

基于微信小程序的自习室选座系统/基于Java的自习室选座系统/自习室管理系统的设计与实现

获取源码联系方式请查看文章结尾&#x1f345; 摘要 自习室选座是学校针对用户必不可少的一个部分。在学校的整个过程中&#xff0c;学生担负着最重要的角色。为满足如今日益复杂的管理需求&#xff0c;各类微信小程序自习室选座也在不断改进。本课题所设计的小程序自习室选座系…

npm下载pnpm

一、提供node_global和node_cache的文件夹 若不存在&#xff0c;可自行新建文件夹 二、配置环境变量 配置NODE_PATH变量&#xff1a; 配置Path变量&#xff1a; 三、执行cmd指令 npm config set prefix "D:\Configure\nodejs\node_global" npm config set cache &…

cdga|数据治理难题破解:策略与实施路径

随着信息技术的飞速发展&#xff0c;数据已成为企业最宝贵的资产之一。然而&#xff0c;数据治理的复杂性也随之增加&#xff0c;如何有效管理、保护和利用数据成为摆在企业面前的一大难题。本文将从数据治理的挑战入手&#xff0c;探讨其破解策略与实施路径。 数据治理的挑战 …

华为IoTDA平台下发MQTT消息

前一篇博文介绍了如何使用MQTTX连接华为IoTDA平台并上报消息&#xff0c;本文介绍一下如何下发消息。 IoT设备接入平台支持MQTT协议设备进行命令下发&#xff0c;属性设置&#xff0c;属性查询以及消息下发等操作。 在进入指定设备的页面后&#xff0c;选择“云端下发”&#…

洛谷 P9854 [CCC 2008 J1] Body Mass Index

这题让我们计算出 BMI 值&#xff0c;随后判断属于哪个等级。 BMI 值计算公式&#xff1a; ​​​​​​​ ​​​​​​​ ​​​​​​​ ​​​​​​​ ​​​​​​​。 BMI 范围 对应信息 …

element-plus时间组件el-date-picker只能选择当前及之前日期

<el-date-picker v-model"timeVal" type"daterange" value-format"YYYY-MM-DD" range-separator"To" start-placeholder"开始时间" end-placeholder"结束时间" />默认是这样的&#xff0c;需要绑定disabled…

安卓手机怎么恢复出厂设置?之后如何恢复数据?3个技巧解决

随着时间的推移&#xff0c;手机可能会遇到性能下降、系统崩溃或其他问题。在这种情况下&#xff0c;恢复出厂设置成为了一个常见的解决方案。安卓手机怎么恢复出厂设置&#xff1f;如何在恢复出厂设置后恢复数据呢&#xff1f;本文将详细解答这些问题&#xff0c;并分享3个数据…

JavaWeb-Servlet(1)-Servlet程序、请求处理、继承体系

目录 什么是Servlet 手动实现Servlet程序 ​编辑url地址如何定位到Servlet程序去访问 Servlet的生命周期 ​编辑GET和POST请求的分发处理 通过继承HttpServlet类实现Servlet程序 IDEA菜单生成Servlet程序 Servlet类的继承体系 ServletConfig类 ServletContext类 什么…

Elasticsearch 7.x入门学习-Java API操作

1 创建项目 在idea开发工具中创建Maven项目 修改 pom 文件&#xff0c;增加 Maven 依赖关系 <dependencies><dependency><groupId>org.elasticsearch</groupId><artifactId>elasticsearch</artifactId><version>7.8.0</versi…

2024恶意样本提交激励计划:年中特别回馈惊喜来袭

恶意样本提交激励计划 “恶意样本提交激励计划”由CACTER邮件安全发起&#xff0c;主要目的是更好地帮助客户排查潜在风险问题&#xff0c;同时丰富Coremail邮件安全大数据中心威胁邮件云端特征库&#xff0c;共同提升Coremail邮件安全大数据中心的识别能力&#xff0c;共同建…

别错过!2024年苹果iPhone AI革命:揭秘技术突破与未来蓝图

本文首发于公众号“AntDream”&#xff0c;欢迎微信搜索“AntDream”或扫描文章底部二维码关注&#xff0c;和我一起每天进步一点点 2024年&#xff0c;苹果公司的iPhone手机在技术创新和系统升级方面展现出一系列亮点&#xff0c;预示着苹果在智能手机领域的持续领导地位。以下…

【python】Python中采集Prometheus数据,进行数据分析和可视化展示

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

openEuler安装docker,加速镜像拉取

文章目录 文章来源1.配置镜像源2.编辑配置文件3.安装想要的版本4. ~ 原神&#xff01;5.由于很多镜像无法拉取配置镜像源 文章来源 http://t.csdnimg.cn/zYDYy 原文连接 由于之前的仓库不让用且 1.配置镜像源 由于 国外的镜像仓库好多不让用 所以配置阿里的镜像源 yum-confi…

MySQL之视图和索引

新建数据库 插入数据 处理表 1. 2. 3. mysql> alter table sc add unique index SC_INDEX (sno asc,cno asc); 4. mysql> create view stu_info as select student.sno,ssex,sc.cno,score from student join sc on student.snosc.sno; 5. mysql> drop index S…

VD2120-DB可替代HY2120-DB 两串可充电锂电池保护IC

VD2120系列10,内置高精度电压检测电路和延时电路&#xff0c;是用于2节串联锂离子/锂聚合物可再充电电池的保护IC。VD2120系列IC适合于对2节串联可再充电锂离子/锂聚合物电池的过充电、过放电和过电流进行保护。 VD2120-DB的参数如下 HY2120-DB的参数如下 参数上面的使用上基本…

LeetCode - #103 二叉树的锯齿形层序遍历

文章目录 前言1. 描述2. 示例3. 答案关于我们 前言 我们社区陆续会将顾毅&#xff08;Netflix 增长黑客&#xff0c;《iOS 面试之道》作者&#xff0c;ACE 职业健身教练。&#xff09;的 Swift 算法题题解整理为文字版以方便大家学习与阅读。 LeetCode 算法到目前我们已经更新…

销售分析,奥威BI,销售好帮手

【销售分析&#xff0c;奥威BI&#xff0c;销售好帮手】 在商海浮沉中&#xff0c;销售数据是企业最宝贵的资产之一&#xff0c;它不仅反映了市场的反馈&#xff0c;更是指引企业未来战略方向的灯塔。奥威BI&#xff08;Business Intelligence&#xff09;&#xff0c;作为数据…

【实现100个unity特效之8】使用ShaderGraph实现2d贴图中指定部分局部发光效果

最终效果 寒冰法师 火焰法师 文章目录 最终效果寒冰法师火焰法师 素材一、功能分析实现方法基本思路Unity的Bloom后处理为什么关键部位白色&#xff1f;最终结果 二、 新建URP项目三、合并图片四、使用PS制作黑白图片方法一 手动涂鸦方法二 魔棒工具1. 拖入图片进PS&#xff0…