行为型设计模式——观察者模式

观察者模式

观察者模式也不难,这个模式用大白话将就是若干个观察者类都订阅一个发布类(被观察者类),当发布者需要发表消息的时候,观察者都能够收到消息。**定义:**又被称为发布-订阅(Publish/Subscribe)模式,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态变化时,会通知所有的观察者对象,使他们能够自动更新自己。

在观察者模式中有如下角色:

  • Subject:抽象主题(抽象被观察者),抽象主题角色把所有观察者对象保存在一个集合里,每个主题都可以有任意数量的观察者,抽象主题提供一个接口,可以增加和删除观察者对象。
  • ConcreteSubject:具体主题(具体被观察者),该角色将有关状态存入具体观察者对象,在具体主题的内部状态发生改变时,给所有注册过的观察者发送通知。
  • Observer:抽象观察者,是观察者的抽象类,它定义了一个更新接口,使得在得到主题更改通知时更新自己。
  • ConcrereObserver:具体观察者,实现抽象观察者定义的更新接口,以便在得到主题更改通知时更新自身的状态。

案例

【例】微信公众号订阅

在使用微信公众号时,大家都会有这样的体验,当你关注的公众号中有新内容更新的话,它就会推送给关注公众号的微信用户端。我们使用观察者模式来模拟这样的场景,微信用户就是观察者,微信公众号是被观察者,有多个的微信用户关注了程序猿这个公众号。

类图如下:

在这里插入图片描述

代码如下:

定义抽象观察者类,里面定义一个更新的方法

public interface Observer {
    void update(String msg);
}

定义具体观察者类,微信用户是观察者,里面实现了更新的方法

public class WeChatUser implements Observer{
    private String name;
    public WeChatUser(String name){
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public void update(String msg) {
        System.out.println("通过网络将 '"+msg+"' 发送给了"+name);
    }
}

定义抽象主题类,提供了attach、detach、notify三个方法

public interface Subject {
    //增加订阅者
    public void attach(Observer observer);

    //删除订阅者
    public void detach(Observer observer);

    //通知订阅者更新消息
    public void notify(String message);
}

微信公众号是具体主题(具体被观察者),里面存储了订阅该公众号的微信用户,并实现了抽象主题中的方法。其实这个类只是封装了观察者(订阅者)的操作:

public class SubscriptionSubject implements Subject{
    //储存订阅公众号的微信用户
    private List<Observer> weChatUserList = new ArrayList<Observer>();
    @Override
    public void attach(Observer observer) {
        weChatUserList.add(observer);
    }

    @Override
    public void detach(Observer observer) {
        weChatUserList.remove(observer);
    }

    @Override
    public void notify(String message) {
        for (Observer o : weChatUserList){
            o.update(message);
        }
    }
}

客户端程序

public class Main {
    public static void main(String[] args) {
        // 微信公众号
        SubscriptionSubject subscriptionSubject = new SubscriptionSubject();

        // 实例化用户
        WeChatUser user1 = new WeChatUser("Toy");
        WeChatUser user2 = new WeChatUser("Jay");
        WeChatUser user3 = new WeChatUser("Jack");

        // 订阅公众号
        subscriptionSubject.attach(user1);
        subscriptionSubject.attach(user2);
        subscriptionSubject.attach(user3);

        // 推送消息
        subscriptionSubject.notify("抽取iPhone15,就在今天!");
    }
}

输出结果:

通过网络将 ‘抽取iPhone15,就在今天!’ 发送给了Toy
通过网络将 ‘抽取iPhone15,就在今天!’ 发送给了Jay
通过网络将 ‘抽取iPhone15,就在今天!’ 发送给了Jack

优点

  • 降低了目标与观察者之间的耦合关系,两者之间是抽象耦合关系。
  • 被观察者发送通知,所有注册的观察者都会收到信息【可以实现广播机制】

缺点

  • 如果观察者非常多的话,那么所有的观察者收到被观察者发送的通知会耗时
  • 如果被观察者有循环依赖的话,那么被观察者发送通知会使观察者循环调用,会导致系统崩溃

使用场景

  • 对象间存在一对多关系,一个对象的状态发生改变会影响其他对象。
  • 当一个抽象模型有两个方面,其中一个方面依赖于另一方面时。

JDK中提供的实现

在 Java 中,通过java.util.Observable类和java.util.Observer接口定义了观察者模式,只要实现它们的子类就可以编写观察者模式实例。

1,Observable类

Observable 类是抽象目标类(被观察者),它有一个 Vector 集合成员变量,用于保存所有要通知的观察者对象,下面来介绍它最重要的 3 个方法。

  • void addObserver(Observer o) 方法:用于将新的观察者对象添加到集合中。

  • void notifyObservers(Object arg) 方法:调用集合中的所有观察者对象的 update方法,通知它们数据发生改变。通常越晚加入集合的观察者越先得到通知。

  • void setChange() 方法:用来设置一个 boolean 类型的内部标志,注明目标对象发生了变化。当它为true时,notifyObservers() 才会通知观察者。

2,Observer 接口

Observer 接口是抽象观察者,它监视目标对象的变化,当目标对象发生变化时,观察者得到通知,并调用 update 方法,进行相应的工作。

【例】订阅微信公众号

微信公众号是被观察者,继承java.util.Observable,然后重写几个方法即可,如下:

import java.util.Observable;
import java.util.Observer;
// 微信公众号是发布者(被观察者)
public class SubscriptionSubject extends Observable {
    String subName; // 公众号名字
    public SubscriptionSubject(String name){
        this.subName = name;
    }

    public String getSubName() {
        return subName;
    }

    @Override
    public synchronized void addObserver(Observer o) {
        System.out.println("微信公众号订阅数+1");
        super.addObserver(o);
    }

    @Override
    public synchronized void deleteObserver(Observer o) {
        System.out.println("微信公众号订阅数-1");
        super.deleteObserver(o);
    }

    @Override
    public void notifyObservers(Object arg) {
        System.out.println("微信公众号发布文章");
        super.notifyObservers(arg);
    }

    public void publishContent(String msg){
        System.out.println("发布内容为:"+msg);
        super.setChanged(); // changed = true
        notifyObservers(msg);  // 通知所有订阅者(观察者)
    }
}

微信用户是一个观察者,所以需要让其实现java.util.Observer接口,重写update方法:

// 微信用户是观察者(订阅者)
public class WeChatUser implements Observer {
    private String name;
    public WeChatUser(String name){
        this.name = name;
    }
    public String getName() {
        return name;
    }
    @Override
    public void update(Observable o, Object arg) {
        // 由发布者,被观察者o调用,arg 是notifyObservers(msg) 的参数msg
        String subName = ((SubscriptionSubject) o).getSubName();
        System.out.println("我是用户"+name+",收到了公众号消息:"+subName+"发来的消息"+(String) arg);
    }
}

客户端代码

public class Main {
    public static void main(String[] args) {
        // 创建公众号(被观察者)
        SubscriptionSubject sub = new SubscriptionSubject("矩阵科学");
        // 创建微信用户(观察者)
        WeChatUser user1 = new WeChatUser("Jay");
        WeChatUser user2 = new WeChatUser("Tom");
        WeChatUser user3 = new WeChatUser("Jack");

        sub.addObserver(user1);
        sub.addObserver(user2);
        sub.addObserver(user3);

        sub.publishContent("欢迎大家关注我的公众号!明天晚上给大家抽iPhone15,谢谢!");

        sub.deleteObserver(user1);
    }
}

结果输出:

微信公众号订阅数+1
微信公众号订阅数+1
微信公众号订阅数+1
发布内容为:欢迎大家关注我的公众号!明天晚上给大家抽iPhone15,谢谢!
微信公众号发布文章
我是用户Jack,收到了公众号消息:矩阵科学发来的消息欢迎大家关注我的公众号!明天晚上给大家抽iPhone15,谢谢!
我是用户Tom,收到了公众号消息:矩阵科学发来的消息欢迎大家关注我的公众号!明天晚上给大家抽iPhone15,谢谢!
我是用户Jay,收到了公众号消息:矩阵科学发来的消息欢迎大家关注我的公众号!明天晚上给大家抽iPhone15,谢谢!
微信公众号订阅数-1

参考内容:

传智播客设计模式相关笔记(主要)
https://zhuanlan.zhihu.com/p/77275289

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Making Large Language Models Perform Better in Knowledge Graph Completion

Making Large Language Models Perform Better in Knowledge Graph Completion 基本信息 博客贡献人 鲁智深 作者 Yichi Zhang, Zhuo Chen, Wen Zhang, Huajun Chen 隶属于浙江大学计算机学院和软件学院 摘要 本文主要探讨了如何将有用的知识图谱结构信息融入大语言模型中…

线性布局(Row/Column)

目录 1、概述 2、基本概念 3、布局子元素在排列方向上的间距 3.1、Column容器内排列方向上的间距 3.2、Row容器内排列方向上的间距 4、布局子元素在交叉轴上的对齐方式 4.1、Column容器内子元素在水平方向上的排列 4.2、Row容器内子元素在垂直方向上的排列 5、布局子元…

Sam Altman 与同性男友结婚;传微软正讨论亚洲研究院去留丨 RTE 开发者日报 Vol.125

开发者朋友们大家好&#xff1a; 这里是 「RTE 开发者日报」 &#xff0c;每天和大家一起看新闻、聊八卦。我们的社区编辑团队会整理分享 RTE &#xff08;Real Time Engagement&#xff09; 领域内「有话题的 新闻 」、「有态度的 观点 」、「有意思的 数据 」、「有思考的 文…

Python实现简易版选课系统

嗨喽&#xff0c;大家好呀~这里是爱看美女的茜茜呐 需求 学生选课系统&#xff1a; 学生 信息&#xff1a;学号&#xff0c;姓名&#xff0c;住址&#xff0c;选的课程列表 功能&#xff1a; 查看&#xff1a;查看该学生所有课程添加课程&#xff1a;把选好得课程添加到课程列…

Python数据分析案例31——中国A股的月份效应研究(方差分析,虚拟变量回归)

案例背景 本次案例是博主本科在行为金融学课程上做的一个小项目&#xff0c;最近看很多经管类的学生作业都很需要&#xff0c;我就用python来重新做了一遍。不弄那些复杂的机器学习模型了&#xff0c;经管类同学就用简单的统计学方法来做模型就好。 研究目的 有效市场假说是现…

基于ssm社区医疗保健监控系统+vue论文

摘 要 如今社会上各行各业&#xff0c;都喜欢用自己行业的专属软件工作&#xff0c;互联网发展到这个时候&#xff0c;人们已经发现离不开了互联网。新技术的产生&#xff0c;往往能解决一些老技术的弊端问题。因为传统社区医疗保健信息管理难度大&#xff0c;容错率低&#x…

生成式人工智能研究焦点:揭秘基于扩散的模型

生成式人工智能研究焦点&#xff1a;揭秘基于扩散的模型 文章目录 生成式人工智能研究焦点&#xff1a;揭秘基于扩散的模型去噪扩散是什么让扩散发挥作用&#xff1f;采样生成图像的设计选择以更少的步骤理顺流程在低噪音水平下步骤高阶求解器可实现更准确的步骤训练降噪器的设…

Lagrange对偶法

这里写自定义目录标题 5.1.1 The Lagrangian5.1.2 The Lagrange dual function5.2 The Lagrange dual problem5.2.3 Strong duality and Slater’s constraint qualification5.2.3 Strong duality and Slater’s constraint qualification5.5.3 KKT optimality conditions Lagr…

C 语言每日一题——旋转数组的最小数字

一、题目内容 提供一下该OJ题的链接&#xff1a;旋转数组的最小数字_牛客题霸_牛客网 (nowcoder.com) 二、题目分析 通过示例1可知&#xff0c;我们写代码的目的是在数组中找到一个最大值&#xff0c;并且返回来&#xff1b; 我们很容易的会想到创建一个变量&#xff1a;int…

天软特色因子看板 (2024.1 第6期)

该因子看板跟踪天软特色因子A04001(当日趋势强度)&#xff0c;该因子为反映股价走势趋势强弱&#xff0c;用以刻画股价走势趋势强弱&#xff0c;abs(值)越接近1&#xff0c;趋势 性越强&#xff0c;符号代表涨跌方向。 今日为该因子跟踪第6期&#xff0c;跟踪其在SW801040 (申万…

深入理解UML中的继承关系

深入理解UML中的继承关系 在面向对象的设计中&#xff0c;继承关系是构建清晰、可维护系统的关键。统一建模语言&#xff08;UML&#xff09;提供了一种标准化的方法来可视化这些关系。本文将深入探讨UML中的继承关系&#xff0c;并探讨它如何在代码中体现。 什么是继承关系&a…

如何修复DLL错误或丢失的问题,这里提供几种方法

DLL错误是指DLL文件的任何错误&#xff0c;一种以.dll文件扩展名结尾的文件。 DLL错误可能出现在微软的任何操作系统中&#xff0c;包括Windows 10、Windows 8、Windows 7、Windows Vista和Windows XP。 DLL错误尤其麻烦&#xff0c;因为存在许多这样类型的文件&#xff0c;所…

pyx文件编译为pyd/so文件(分别在windows/linux系统下)

Python有以下几种类型的文件&#xff1a; py&#xff1a;Python控制台程序的源代码文件pyx&#xff1a;是Python语言的一个编译扩展&#xff0c;它实际上是Cython语言的源代码文件&#xff08;可以理解为既支持Python语言也支持C/C&#xff09;。pyc&#xff1a;Python字节码文…

关于lora的理解

非常推荐看参考中的文章&#xff0c;对lora的原理和代码&#xff0c;包括细节都讲得很清楚&#xff01; 参考&#xff1a;【OpenLLM 007】大模型炼丹术之小参数撬动大模型-万字长文全面解读PEFT参数高效微调技术 - 知乎 (zhihu.com)图解大模型微调系列之&#xff1a;大模型低秩…

创新技术高精度直线模组技术优势及应用详解

近年来&#xff0c;随着工业自动化转型升级不断提速&#xff0c;市场对优质直线模组的需求量直线上升&#xff0c;而直线模组拥有单体运动速度快、重复定位精度高、本体质量轻、占设备空间小、寿命长等优势&#xff0c;在机械设备领域备受青睐。作为深耕工业自动化产品市场多年…

软件测试最新项目合集【商城、外卖、银行、金融等等.......】

​项目一&#xff1a;ShopNC商城 项目概况&#xff1a; ShopNC商城是一个电子商务B2C电商平台系统&#xff0c;功能强大&#xff0c;安全便捷。适合企业及个人快速构建个性化网上商城。 包含PCIOS客户端Adroid客户端微商城&#xff0c;系统PC后台是基于ThinkPHP MVC构架开发的…

谁在成为大模型的“AI运营”?

在过去的一段时间里&#xff0c;“AI-native”成为所有工具的一个显著探索趋势&#xff0c;不论是算力集群的智算中心&#xff0c;还是数据库侧的向量数据库&#xff0c;再或者是不断进化的算法&#xff0c;都在以一种更适配大模型架构的方式被推演出来。 那么&#xff0c;大模…

四川云汇优想教育咨询有限公司引领电商未来

四川云汇优想教育咨询有限公司&#xff0c;一家在电商服务领域崭露头角的领军企业&#xff0c;致力于为广大客户提供最优质、最全面的电商服务。作为业界翘楚&#xff0c;云汇优想凭借其卓越的服务品质和强大的技术实力&#xff0c;在激烈的市场竞争中独树一帜&#xff0c;赢得…

【数据库原理】(24)数据库安全性策略

数据库安全性是数据库管理系统&#xff08;DBMS&#xff09;中一个至关重要的方面。它指的是保护数据库免受非授权访问和恶意操作&#xff0c;包括数据泄露、修改、破坏等。 多层安全模型 在典型的计算机系统安全模型中&#xff0c;安全措施被设置在不同层级&#xff1a; 应用…

第11章 GUI Page489~494 步骤三十 保存画板文件02 实现存盘函数SaveFile

工程添加新头文件 tool_4_save_load.hpp 增加源文件 tool_4_save_load.cpp IItem类增加保存到流的接口&#xff1a; 在直线&#xff0c;圆&#xff0c;十字形&#xff0c;方框&#xff0c;文字类中实现这个接口 回到主框架窗口&#xff0c;实现保存文件的函数SaveFile 首先封…