Observer 模式

news2024/11/18 21:35:39

文章目录

  • 💡问题引入
  • 💡概念
  • 💡例子
  • 💡总结

💡问题引入

假设有一个在线商店系统,用户可以订阅商品的库存通知。当某个商品的库存数量发生变化时,系统会自动发送通知给所有订阅了该商品的用户。设计一个使用观察者模式的系统来实现这个功能。

💡概念

定义对象间的一种一对多(变化)的依赖关系,以便当一个对象(Subject)的状态发生改变时,所有依赖它的对象都得到通知并自动更新

💡例子

  • 观察者模式实例
#include <iostream>
#include <list>
#include <string>

// 观察者接口
class Observer {
public:
    virtual void update(const std::string& message) = 0;
};

// 被观察者类
class Subject {
private:
    std::list<Observer*> observers;   // 观察者列表
    std::string message;                // 存储消息

public:
    // 添加观察者
    void attach(Observer* observer) {
        observers.push_back(observer);
    }

    // 移除观察者
    void detach(Observer* observer){
        m_ObsList.remove(observer);
    }
    
    // 通知观察者
    void notify() {
        for (auto observer : observers) {
            observer->update(message);
        }
    }

    // 设置消息并触发通知
    void setMessage(const std::string& newMessage) {
        message = newMessage;
        notify();
    }
};

// 具体观察者类
class ConcreteObserver : public Observer {
private:
    std::string name;   // 观察者名称

public:
    // 构造函数
    ConcreteObserver(const std::string& observerName) : name(observerName) {}

    // 实现观察者接口的update方法
    void update(const std::string& message) {
        std::cout << name << " received the message: " << message << std::endl;
    }
};

int main() {
    // 创建主题
    Subject subject;

    // 创建观察者
    ConcreteObserver observer1("Observer 1");
    ConcreteObserver observer2("Observer 2");
    ConcreteObserver observer3("Observer 3");

    // 将观察者添加到主题中
    subject.attach(&observer1);
    subject.attach(&observer2);
    subject.attach(&observer3);

    // 设置主题的消息,触发通知
    subject.setMessage("Hello, observers!");

    // 将观察者从主题中删除
    subject.detach(&observer2);

    // 再次设置主题的消息,触发通知,此时observer2不会收到消息
    subject.setMessage("Goodbye!");

    return 0;
}

观察者模式结构类图
在这里插入图片描述

问题分析
➢在软件构建过程中,我们需要为某些对象建立一种“通知依赖关系”一一个对象(目标对象)的状态发生改变,所有的依赖对
象(观察者对象)都将得到通知。如果这样的依赖关系过于紧密,将使软件不能很好地抵御变化。
➢使用面向对象技术,可以将这种依赖关系弱化,并形成一种稳定的依赖关系。从而实现软件体系结构的松耦合。

  • 问题引入的实现代码
// 观察者接口
class Observer {
public:
    virtual void update(const std::string& productId, int stockCount) = 0;
};

// 被观察者类(商品)
class Product {
private:
    std::string productId;
    int stockCount;
    std::list<Observer*> observers;

public:
    Product(const std::string& id) : productId(id), stockCount(0) {}

    // 添加观察者
    void attach(Observer* observer) {
        observers.push_back(observer);
    }

    // 移除观察者
    void detach(Observer* observer) {
        observers.remove(observer);
    }

    // 通知观察者
    void notify() {
        for (auto observer : observers) {
            observer->update(productId, stockCount);
        }
    }

    // 设置库存数量并触发通知
    void setStockCount(int count) {
        stockCount = count;
        notify();
    }
};

// 具体观察者类(用户)
class User : public Observer {
private:
    std::string userId;

public:
    User(const std::string& id) : userId(id) {}

    // 实现观察者接口的update方法
    void update(const std::string& productId, int stockCount) {
        std::cout << "User " << userId << ": Product " << productId << " has a new stock count of " << stockCount << std::endl;
    }
};

int main() {
    // 创建商品
    Product product1("12345");
    Product product2("67890");

    // 创建用户
    User user1("Alice");
    User user2("Bob");

    // 将用户添加为商品的观察者
    product1.attach(&user1);
    product1.attach(&user2);
    product2.attach(&user1);

    // 设置商品的库存数量,触发通知
    product1.setStockCount(10);
    product2.setStockCount(5);

    // 将某个用户从商品的观察者列表中移除
    product1.detach(&user2);

    // 再次设置商品的库存数量,触发通知
    product1.setStockCount(15);

    return 0;
}

运行结果如图
在这里插入图片描述

💡总结

➢使用面向对象的抽象, Observer模式使得我们可以独立地改变目标与观察者,从而使二者之间的依赖关系达致松耦合。
➢目标发送通知时,无需指定观察者,通知(可以携带通知信息作为参数)会自动传播。
➢观察者自己决定是否需要订阅通知,目标对象对此一无所知。
➢Observer模式是基于事件的UI框架中非常常用的设计模式,也是MVC模式的一一个重要组成部分。

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

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

相关文章

Anaconda下载安装及配置pytorch环境

先解释一下Python、Anaconda、Pytorch是啥 Python是一种广泛使用的编程语言&#xff0c;在许多领域都有应用。它具有简洁的语法&#xff0c;易于学习&#xff0c;并且有大量的第三方库可以使用。 Anaconda是一个Python的包和环境管理软件&#xff0c;提供了许多用于数据科学&a…

融资利率选哪家好?

第一&#xff1a;怎么理解融资融券&#xff1f; 融资融券交易&#xff0c;又称“证券信用交易”&#xff0c;分为融资交易和融券交易。是指投资者通过向具有融资融券业务资格的证券公司提供担保物&#xff0c;借入资金买入证券&#xff08;融资交易&#xff09;或借入证券并卖…

前端基础篇-深入了解用 HTML 与 CSS 实现标题排版

&#x1f525;博客主页&#xff1a; 【小扳_-CSDN博客】 ❤感谢大家点赞&#x1f44d;收藏⭐评论✍ 文章目录 1.0 HTML 与 CSS 概述 2.0 HTML - 标题排版 2.1 图片标签 2.2 标题标签 2.3 水平标签 2.4 实现标题排版 3.0 HTML - 标题样式(style 样式) 3.1 CSS 的引入方式 3.2…

docker学习入门篇

1、docker简介 docker官网&#xff1a; www.docker.com dockerhub官网&#xff1a; hub.docker.com docker文档官网&#xff1a;docs.docker.com Docker是基于Go语言实现的云开源项目。 Docker的主要目标是&#xff1a;Build, Ship and Run Any App, Anywhere(构建&…

ScaleKD: Distilling Scale-Aware Knowledge in Small Object Detector

ScaleKD: Distilling Scale-Aware Knowledge in Small Object Detector在小目标检测器中提取尺度感知知识 摘要 尽管通用目标检测取得了显著的成功&#xff0c;但小目标检测&#xff08;SOD&#xff09;的性能和效率仍然令人不满意。与现有的努力平衡推理速度和SOD性能之间的…

华为数通方向HCIP-DataCom H12-821题库(多选题:121-140)

第121题 以下哪些事件会导致IS-IS产生一个新的LSP? A、引入的IP路由发送变化 B、周期性更新 C、接口开销发生了变化 D、邻接Up或Down 【参考答案】ABCD 【答案解析】 第122题 以下哪些协议既支持网络配置管理又支持网络监控管理? A、Telemetry B、NETCONF C、SNMP D、LLDP …

机器视觉学习(一)—— 认识OpenCV、安装OpenCV

目录 一、认识OpenCV 二、通过pip工具安装OpenCV 三、PyCharm安装OpenCV 一、认识OpenCV OpenCV&#xff08;Open Source Computer Vision Library&#xff0c;开源计算机视觉库&#xff09;是一个跨平台的计算机视觉库&#xff0c;最初由威尔斯理工学院的Gary Bradski于199…

Node.Js编码注意事项

Node.js 中不能使用 BOM 和 DOM 的 API&#xff0c;可以使用 console 和定时器 APINode.js 中的顶级对象为 global&#xff0c;也可以用 globalThis 访问顶级对象 浏览器端js的组成 Node.js中的JavaScript组成 相比较之下发现只有console与定时器是两个API所共有的&#xff…

QQ邮箱API的安全性和隐私保护措施有哪些?

QQ邮箱API接口有哪些功能&#xff1f;如何申请电子邮箱API接口&#xff1f; QQ邮箱作为国内广受欢迎的电子邮箱服务&#xff0c;其API接口的安全性和隐私保护措施更是备受关注。那么&#xff0c;QQ邮箱API的安全性和隐私保护措施究竟有哪些呢&#xff1f;接下来&#xff0c;就…

ABAP接口部分-Web Service提供者与消费者

ABAP接口部分-Web Service提供者与消费者 文章目录 ABAP接口部分-Web Service提供者与消费者Web Service提供者Web Service测试配置[SOA网址](https://mysap.goodsap.cn:44300/sap/bc/webdynpro/sap/appl_soap_management )测试 Web Service消费者创建Services Consumer消费者创…

C# 中 Replace 字符串操作方法

在 C# 中&#xff0c;Replace 是一个字符串操作方法&#xff0c;用于替换字符串中的指定字符或子字符串。它接受两个参数&#xff1a;要查找和替换的字符串。Replace 方法在源字符串中查找所有匹配的字符或子字符串&#xff0c;并用指定的替换字符串进行替换。 下面是 Replace…

CV论文--2024.3.7

1、FAR: Flexible, Accurate and Robust 6DoF Relative Camera Pose Estimation 中文标题&#xff1a;FAR&#xff1a;灵活、准确和稳健的6DoF相机相对姿态估计 简介&#xff1a;在计算机视觉领域&#xff0c;估计图像之间的相对相机姿态一直是一个关键问题。通常&#xff0c;…

多核多cluster多系统之间缓存一致性概述

目录 1.思考和质疑2.怎样去维护多核多系统缓存的一致性2.1多核缓存一致性2.2多Master之间的缓存一致性2.3dynamIQ架构同一个core中的L1和L2 cache 3.MESI协议的介绍4.ACE维护的缓存一致性5.软件定义的缓存和替换策略6.动图示例 本文转自 周贺贺&#xff0c;baron&#xff0c;代…

Day6 java 常用API

文章目录 1、Calendar1.1 Calendar日历对象 2、JDK8 之后新增的时间类2.1 LocalDate、LocalTime 、LocalDateTime2.2 ZoneId 、ZoneIdTime2.3 Instant2.4 DateTimeFormatter2.5 Period2.6 Duration 1、Calendar 在了解calendar之前&#xff0c;先用SimpleDateFormat 写一个小例…

企企通解决方案总监汤水卿:打造企业间接采购数字化平台,赋能供应链高效跃进新篇章

3月5日&#xff0c;国务院总理李强在政府工作报告中提出&#xff0c;制定支持数字经济高质量发展政策&#xff0c;积极推进数字产业化、产业数字化&#xff0c;促进数字技术和实体经济深度融合。 近日&#xff0c;企企通受邀参加了2024华南采购峰会&#xff0c;与各行各业的采购…

C#/.NET/.NET Core拾遗补漏合集(持续更新)

前言 在这个快速发展的技术世界中&#xff0c;时常会有一些重要的知识点、信息或细节被忽略或遗漏。《C#/.NET/.NET Core拾遗补漏》专栏我们将探讨一些可能被忽略或遗漏的重要知识点、信息或细节&#xff0c;以帮助大家更全面地了解这些技术栈的特性和发展方向。 GitHub开源地…

电脑右下角出线白色弹窗的解决方法

电脑无缘无故&#xff0c;在右下角出现一个白色弹窗&#xff0c;无法关闭&#xff0c;非常恶心&#xff0c;后来经过查询&#xff0c;发现可能是360之类的弹bug&#xff0c;解决只需要&#xff1a; 1、鼠标左键 点击一下白框 2、键盘输入 AltF4 虽不是技术问题&#xff0c;但解…

Github上那些好用的安全工具(三)

专注于web漏洞挖掘、内网渗透、免杀和代码审计&#xff0c;感谢各位师傅的关注&#xff01;网安之路漫长&#xff0c;与君共勉&#xff01; URLFinder 一款快速提取网页信息的工具。该项目可以快速爬取网页上的 URL 地址、JS 文件里的 API 接口等信息&#xff0c;支持批量抓取、…

日期工具的逻辑与数据请求函数的完善

src\libs\utils.js 获取当前日期格式 /*** 获取当前日期格式* param {*} field * returns */ function getNowDate(field) {const date new Date()let year date.getFullYear(),month date.getMonth() 1,day date.getDate()switch (field) {case day:return ${year}-${mo…

Halcon测量专栏-圆度

1.前言 1.1什么是圆度 圆度是指工件的横截面接近理论圆的程度&#xff0c;最大半径与最小半径之差为0时&#xff0c;圆度为0&#xff0c;测量工具为圆度仪&#xff0c;用途是测环形工件的圆度。圆度是限制实际圆对理想圆变动量的一项指标&#xff0c;其公差带是以公差值t为半…