4. 观察者模式

目录

  • 一、现实应用场景
  • 二、初步实现
    • 2.1 实现方案1
    • 2.2 实现方案2
  • 三、观察者模式
    • 3.1 应用场景
    • 3.2 详解
    • 3.3 实现
    • 3.4 设计类图
  • 四、实现
  • 五、更多

一、现实应用场景

  1. 教师的手机号改变之后要通知给所有学生
  2. 如果有一个学生没有通知到位就会产生遗漏
  3. 如何自动完成

二、初步实现

2.1 实现方案1

  • 定义学生和教师类
  • 教师类设置set和get方法
  • 教师的手机号修改后要依次调用所有学生的类重新设置
#include <iostream>class Student
{
private:std::string m_name;std::string m_tPhone;public:Student(const std::string& name){m_name = name;}void setTPhoneNubmer(const std::string& phone){m_tPhone = phone;}void show(){std::cout << "Name: " << m_name << " Teacher's Phone: " << m_tPhone << std::endl;}
};class Teacher
{
private:std::string m_phone;public:Teacher(const std::string& phone){m_phone = phone;}void setPhone(const std::string& phone){m_phone = phone;}std::string getPhone() const {return m_phone;}
};int main()
{Teacher zwz("12345");Student li("LiLei");Student Jie("Jie");Student wcz("wcz");li.setTPhoneNubmer(zwz.getPhone());Jie.setTPhoneNubmer(zwz.getPhone());wcz.setTPhoneNubmer(zwz.getPhone());li.show();Jie.show();wcz.show();//修改zwz.setPhone("67890");li.setTPhoneNubmer(zwz.getPhone());Jie.setTPhoneNubmer(zwz.getPhone());wcz.setTPhoneNubmer(zwz.getPhone());li.show();Jie.show();wcz.show();return 0;
}

2.2 实现方案2

  • 学生类中拥有一个教师的实例,该实例由外部传入
  • 只要教师的手机号在外部修改,那个学生类中只需要通过getPhone()函数即可得到教师的手机号
  • 实现过程如下
#include <iostream>class Teacher
{
private:std::string m_phone;public:Teacher(const std::string& phone){m_phone = phone;}void setPhone(const std::string& phone){m_phone = phone;}std::string getPhone() const{return m_phone;}
};class Student
{
private:std::string m_name;std::string m_tPhone;const Teacher* m_teacher;public:Student(const std::string& name, const Teacher* teacher){m_name = name;m_teacher = teacher;}void show(){std::cout << "Name: " << m_name << " Teacher's Phone: " << m_teacher->getPhone() << std::endl;}
};int main()
{Teacher zwz("12345");Student li("LiLei", &zwz);Student Jie("Jie", &zwz);Student wcz("wcz", &zwz);li.show();Jie.show();wcz.show();//修改zwz.setPhone("67890");li.show();Jie.show();wcz.show();return 0;
}
  • 存在问题
    • 两个对象间存在紧耦合关系
    • 如果换老师之后,老师的实例还得修改
    • 缺少扩展性与灵活性

三、观察者模式

3.1 应用场景

  • 当对象发生变化,通知给其他对象,需要其他对象做出调整
  • 应用程序的可维护性和重用性较高
  • 互动关系不能体现成类之间的直接调用,对象之间关系的解耦

3.2 详解

  • 观察者模式又称为发布订阅模式
  • 两个角色: 观察者和被观察对象
  • 两者之间存在”观察“的逻辑关联
  • 当被观察者发生改变的时候,观察者就会观察到这样的变化,并且做出相应的响应
  • 观察不是直接调用
  • 实现观察者模式有很多形式,比较直观的一种是注册-> 通知 -> 撤销注册形式。

3.3 实现

  1. 步骤1:观察者将自己注册到被观察对象中,被观察对象将观察者存放在一个容器中。
  2. 步骤2:被观察者对象发生了某种变化,从容器中得到所有注册过的观察者,将变化通知观察者。
  3. 步骤3(可选):观察者告诉被观察者要撤销观察,被观察者从容器中将观察者去除。

3.4 设计类图

在这里插入图片描述

  • ConcreteSubject:
    • 主题对象,被观察者,对应老师。
    • 他有变化时通知ConcreteObserver类的实例(学生)。学生根据变化自动调用update()做出响应。
    • 内部有一个队列存储、移除观察者
    • 当状态发生变化时可以调用notifyObservers()通知观察者
  • ConcreteSubjectConcreteObserver类解耦
    • 学生不只可以观察老师,还可以观察学院、某个同学等。
    • 两个类分别向上抽取了被观察者接口 (Subject)和观察者接口(Observer)

四、实现

#include <iostream>
#include <list>class IObserver
{
public:virtual void update(void* o) = 0;
};class ISubject
{
public:virtual void registerObserver(IObserver* obj) = 0;virtual void removeObserver(IObserver* obj) = 0;virtual void notifyObserver() = 0;
};class Teacher: ISubject
{
private:std::string m_phone;std::list<IObserver*> m_subject;public:void setPhone(const std::string& phone){m_phone = phone;notifyObserver();}std::string getPhone() const{return m_phone;}void registerObserver(IObserver* o){m_subject.push_back(o);}void removeObserver(IObserver* o){m_subject.remove(o);}void notifyObserver(){for (auto item : m_subject){item->update((void*)m_phone.c_str());}}
};class Student: public IObserver
{
private:std::string m_name;std::string m_tPhone;public:Student(const std::string& name){m_name = name;}void update(void* o){m_tPhone = reinterpret_cast<char*>(o);}void show(){std::cout << "Name: " << m_name << " Teacher's Phone: " << m_tPhone << std::endl;}
};int main()
{Teacher zwz;Student li("LiLei");Student Jie("Jie");Student wcz("wcz");Student test("test");zwz.registerObserver(&li);zwz.registerObserver(&Jie);zwz.registerObserver(&wcz);std::cout << "\n*******设置教师手机号为12345*******" << std::endl;zwz.setPhone("12345");li.show();Jie.show();wcz.show();zwz.removeObserver(&wcz); //移除对wcz的通知std::cout << "\n*******对教师手机号进行修改为67890*******" << std::endl;//修改zwz.setPhone("67890");li.show();Jie.show();std::cout << "\n*******不会被改变*******" << std::endl;wcz.show();  //不会被改变return 0;
}
  • 创建观察者接口IObserver(),并规定了更新的行为。
  • 创建被观察者接口ISubject(),并规定了添加、移除和通知观察者的行为。
  • 运行结果
    在这里插入图片描述

五、更多

  • 这个例子中需要在main函数中手动调用注册,可以在Observer对象创建时传入Subject对象,以便自动注册。
  • 详情请参阅 https://gitee.com/piglittle/design_patterns中的 Head_First_Design_Partterns解决方案下的 observer_pattern项目
  • 其详细的类图如下
    请添加图片描述

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

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

相关文章

es 启动中的一些记录

完整修复流程 bash # 1. 创建用户主目录(如果需要) mkdir -p /home/es8 chown es8:es8 /home/es8# 2. 变更 Elasticsearch 目录所有权 chown -R es8:es8 /data/es/elasticsearch-8.17.2/# 3. 调整目录和文件权限 chmod -R 755 /data/es/elasticsearch-8.17.2/ chmod 644 /d…

区块链之拜占庭容错算法——Practical Byzantine Fault Tolerance(PBFT)

实用拜占庭容错算法&#xff08;PBFT&#xff09;是由 Barbara Liskov 和 Miguel Castro 于 90 年代末提出的一种共识算法。原论文链接如下&#xff1a; http://pmg.csail.mit.edu/papers/osdi99.pdf pBFT 被设计为在异步&#xff08;响应请求的时间没有上限&#xff09;系统…

从电子管到CPU

在线verilog转电路图 简单门电路 https://logic.ly/demo/ 数学基础 普通逻辑 与自然语言关系紧密, 亚里士多德三段论,‌‌穆勒五法 , 语言, 语义,概念,定义,辩论, 诈骗 等, 是文科类的逻辑。 离散数学 不连续数学 数理逻辑 命题逻辑与谓词逻辑, 与数学推理关系紧密, 它…

Javase-8.数组的练习

1.查找数组中指定元素(二分查找)以升序数组为例, 二分查找的思路是先取中间位置的元素, 然后使用待查找元素与数组中间元素进行比较&#xff1a; 如果相等&#xff0c;即找到了返回该元素在数组中的下标 如果小于&#xff0c;以类似方式到数组左半侧查找 如果大于&#xff0c;以…

H3CNE综合实验之机器人

H3CNE综合实验之机器人 实验拓扑图实验需求 1.按照图示配置 IP 地址 2.SW1 和 SW2 之间的直连链路配置链路聚合 3.公司内部业务网段为 Vlan10 和 Vlan20;Vlan10 是市场部&#xff0c;Vlan20 是技术部&#xff0c;要求对 Vlan 进行命名以识别; ​ PC8 属于 Vlan10&#xff0c…

2025/7/15——java学习总结

Java IO、Stream、异常与 File 全体系总结&#xff1a;从基础到进阶的完整突破一、核心知识深耕&#xff1a;四大模块的体系与底层逻辑&#xff08;一&#xff09;IO 流&#xff1a;数据传输的基础通道体系架构与核心分类按流向&#xff1a;输入流&#xff08;InputStream/Read…

【轨物方案】当补贴退潮,光伏电站如何回归价值本质?

中国光伏产业正站在一个历史性的拐点。过去&#xff0c;国家补贴的“黄金时代”催生了装机量的爆发式增长&#xff0c;许多电站在建设初期将重心放在了快速并网&#xff0c;却忽视了贯穿2-30年生命周期的运维规划。如今&#xff0c;补贴浪潮逐渐退去&#xff0c;各大企业开始从…

群晖Nas - Docker(ContainerManager)上安装SVN Server和库权限设置问题

上次安装了Gitlab&#xff0c;可以参考这篇&#xff08;群晖Nas - Docker&#xff08;ContainerManager&#xff09;上安装GitLab&#xff09;&#xff0c;今天来搞SVN服务器&#xff0c;废话不多说。 下载镜像 还是先下载镜像&#xff08;garethflowers/svn-server&#xff…

前端打包自动压缩为zip--archiver

安装依赖 pnpm add archiver types/archiver/vitePlugins/autoBuildZip.ts import { Plugin } from vite; import archiver from archiver; import fs from fs;const compressFolder (folderPath: string, outputFilePath: string) > {const output fs.createWriteStream(…

React响应式组件范式:从类组件到Hooks

​引言 在UI开发中&#xff0c;"状态变化自动触发UI更新"的响应式机制是构建动态界面的核心。React通过独特的​​单向数据流​​和​​虚拟DOM&#xff08;Virtual DOM&#xff09;​​ 实现这一目标&#xff0c;但类组件&#xff08;Class Components&#xff09;…

com2tcp工具

com2tcp 是 com0com 套件中的一个实用工具&#xff0c;用于将本地串口&#xff08;COM&#xff09;数据转发到 TCP/IP 网络&#xff0c;或者将 TCP/IP 数据转发到本地串口&#xff0c;实现串口数据的网络透传。 1. com2tcp 基本用法 &#xff08;1&#xff09;安装 com0com 从…

MySQL实操:将Word表格数据导入MySQL表

文章目录 1. 提出任务1.1 Word表格数据1.2 查看商品空表1.3 任务要求2. 完成任务2.1 借助AI2.1.1 利用AI生成SQL语句2.1.2 在Navicat里执行查询2.1.3 查看商品表记录2.2 借助Excel2.2.1 将Word表格数据复制到Excel2.2.2 新建商品表2.2.3 利用导入向导将电子表格数据导入商品表2…

什么是Podman?能否替代Docker?Podman快速入门

什么是PodmanPodman&#xff08;POD Manager&#xff09;是一个开源的无守护进程&#xff08;daemonless&#xff09;容器引擎&#xff0c;用于管理容器、容器镜像、容器卷和网络。它兼容 OCI 标准&#xff0c;可以运行 Docker 镜像&#xff0c;并且设计上与 Docker CLI 命令高…

开通保存图片权限

直接粘贴就可以用 上干货 可以的话希望点个start/* 小程序特有相关 */mp-weixin: {appid: VITE_WX_APPID,setting: {urlCheck: false,minified : true //是否压缩js},usingComponents: true,"lazyCodeLoading": "requiredComponents", //按需注入"pe…

【赵渝强老师】大数据交换引擎Sqoop

Sqoop是SQL To Hadoop的简称&#xff0c;它是一款开源的工具&#xff0c;主要用于在Hadoop&#xff08;Hive&#xff09;与传统的数据库&#xff08;Oracle、MySQL等&#xff09;间进行数据的传递。通过使用Sqoop可以将一个关系型数据库中的数据导进到Hadoop的HDFS中&#xff0…

C++进阶-map的应用

目录 1.预备知识 2.map的补充知识 2.1map的插入方式 2.2访问键和值 2.3map::operator[]的补充 2.4另外一些map的成员函数的补充 3.map的应用实践-力扣刷题-前k个高频单词 3.1解法1 3.2解法2 3.3解法3 4.map的应用实践-力扣刷题-随机链表的复制 4.1C语言解法 4.2C解…

【三维重建工具】NeRFStudio、3D GaussianSplatting、Colmap安装与使用指南

目录 一、NeRFStudio安装1.安装&#xff08;ubuntu系统&#xff09;2.安装&#xff08;windows系统&#xff09; 二、安装tinycudann三、Colmap安装与使用1. 安装依赖2. 安装colmap3.使用colmap3.1 可视化界面使用3.2 Nerfstudio命令行调用Colmap3.3 colmap结果不准时的修复3.4…

Mybatis05-动态sql

一、应用场景MyBatis 的 动态 SQL 是指根据不同的条件动态拼接生成 SQL 语句的能力。它的最大优势是&#xff1a;避免写多个 XML 映射语句、避免 SQL 冗余、提升代码复用性和可维护性。示例1&#xff1a;用户可以通过勾选框&#xff0c;勾选不同的数据进行批量删除&#xff0c;…

VSCODE 选中多行 需要同时按住alt键才可以

在 VS Code 中&#xff0c;如果你发现 必须按住 Alt 键才能选中多行&#xff08;即“列选择”或“块选择”模式&#xff09;&#xff0c;而直接拖动鼠标无法多选&#xff0c;可能是由于以下原因导致的&#xff1a;1. 检查是否启用了“列选择模式”VS Code 默认情况下&#xff1…

2025前端面试真题以及答案-不断整理中,问题来源于牛客真题

一、 项目内存泄露react与vue的渲染机制有哪些不同react fiber架构vue2与3&#xff0c;为什么用proxy代替defineproperty性能优化有哪些三栏布局实现方式重排与重绘一个对话聊天框如何减少重排&#xff08;我回答的是绝对定位&#xff0c;将聊天框定位在下面&#xff0c;类似于…