Observer 模式

文章目录

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

💡问题引入

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

💡概念

定义对象间的一种一对多(变化)的依赖关系,以便当一个对象(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模式的一一个重要组成部分。

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

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

相关文章

Android 13 WMS-动画流程

动画的类型如下 IntDef(flag true, prefix { "ANIMATION_TYPE_" }, value {ANIMATION_TYPE_NONE,ANIMATION_TYPE_APP_TRANSITION,ANIMATION_TYPE_SCREEN_ROTATION,ANIMATION_TYPE_DIMMER,ANIMATION_TYPE_RECENTS,ANIMATION_TYPE_WINDOW_ANIMATION,ANIMATION_TYPE_…

CentOS7.9基于Apache2.4+Php7.4+Mysql8.0架构部署Zabbix6.0LTS 亲测验证完美通过方案

前言: Zabbix 由 Alexei Vladishev 创建,目前由 Zabbix SIA 主导开发和支持。 Zabbix 是一个企业级的开源分布式监控解决方案。 Zabbix 是一款监控网络的众多参数以及服务器、虚拟机、应用程序、服务、数据库、网站、云等的健康和完整性的软件。 Zabbix 使用灵活的通知机制,…

云计算项目八:Harbor

部署企业私有镜像仓库Harbor 私有镜像仓库有许多优点&#xff1a; 节省网络带宽&#xff0c;针对于每个镜像不用每个人都去中央仓库上面去下载&#xff0c;只需要从私有仓库中下载即可提供镜像资源利用&#xff0c;针对于公司内部使用的镜像&#xff0c;推送到本地私有仓库中…

华硕AMD主板开启TPM2.0支持

目录 配置问题设置开启 Firmware TPM开启 Security Device Support保存设置 检查 配置 主板&#xff1a;TUF Gaming B550m-e Wifi   BIOS: 3402 问题 今天更新Win11&#xff0c;告诉我不支持 TPM 2.0&#xff0c;导致更新失败。   网上搜这个问题&#xff0c;基本只提供了…

selenium中ChromeDriver配置,一把过,并且教你伪装

最近正值毕业季&#xff0c;我之前不是写了个问卷星代码嘛&#xff0c;昨晚上有人凌晨1点加我&#xff0c;问我相关内容。 由于我之前C盘重装了一下&#xff0c;导致我很多东西空有其表&#xff0c;实际不能用&#xff0c;借此机会&#xff0c;向大家编写ChromeDriver配置&…

江苏某机场多座智慧公厕上线,黑科技满满打造标杆性机场智慧卫生间

在现代社会&#xff0c;智慧科技正在各个领域中得到广泛应用&#xff0c;机场也不例外。智慧机场是信息化程度、建设标准、功能要求最高的领域&#xff0c;智慧卫生间的建设要求同样是业界的最高标准。智慧公厕源头厂家广州中期科技有限公司&#xff0c;已经建设了浙江某机场、…

SICP解读指南:深度阅读 “计算机领域三巨头” 之一(文末送书)

&#x1f308;个人主页&#xff1a;聆风吟_ &#x1f525;系列专栏&#xff1a;Linux实践室、网络奇遇记 &#x1f516;少年有梦不应止于心动&#xff0c;更要付诸行动。 文章目录 &#x1f4cb;前言一. 书籍介绍1.1 SICP侧重点1.2 SICP章节介绍 二. 书籍推荐2.1 书籍介绍2.2 推…

边缘计算基础知识

目录 边缘计算简介任务卸载简介边缘存储系统 边缘计算简介 边缘计算是指利用靠近数据生成的网络边缘侧的设备&#xff08;如移动设备、基站、边缘服务器、边缘云等&#xff09;的计算能力和存储能力&#xff0c;使得数据和任务能够就近得到处理和执行。 一个典型的边缘计算系…

java集合(泛型数据结构)

1.泛型 1.1泛型概述 泛型的介绍 泛型是JDK5中引入的特性&#xff0c;它提供了编译时类型安全检测机制 泛型的好处 把运行时期的问题提前到了编译期间 避免了强制类型转换 泛型的定义格式 <类型>: 指定一种类型的格式.尖括号里面可以任意书写,一般只写一个字母.例如: …

这可能是最全的Web测试各个测试点,有这一篇就够了

前言 什么是Web测试&#xff1f; Web测试测试Web或Web应用程序的潜在错误。它是在上线前对基于网络的应用程序进行完整的测试。 Web测试检查 功能测试 易用性测试 接口测试 性能测试 安全测试 兼容性测试 1、功能测试 测试网页中的所有链接、数据库连接、网页中用于提交或从…

通过Dockerfile创建镜像

通过Dockerfile创建镜像 Docker 提供了一种更便捷的方式&#xff0c;叫作 Dockerfile docker build命令用于根据给定的Dockerfile构建Docker镜像。 docker build语法&#xff1a; # docker build [OPTIONS] <PATH | URL | -> 1. 常用选项说明--build-arg&#xff0c;设置…

数据结构:顺序表的奥秘

&#x1f389;个人名片&#xff1a; &#x1f43c;作者简介&#xff1a;一名乐于分享在学习道路上收获的大二在校生&#x1f43b;‍❄个人主页&#x1f389;&#xff1a;GOTXX &#x1f43c;个人WeChat&#xff1a;ILXOXVJE&#x1f43c;本文由GOTXX原创&#xff0c;首发CSDN&a…

医药行业五大难题深度剖析:CRM解决方案助力突围

医疗行业关系着民生、经济乃至战备&#xff0c;是国民经济的重要组成部分。虽然近20年来我国医疗行业年均增长率维持在15%之上&#xff0c;但行业发展仍存在诸多问题。引进CRM管理系统可能是一个行之有效的解决方法。文中将为您整理医疗行业目前的五大挑战&#xff0c;以及CRM如…

跟无神学AI之Tensorflow笔记搭建网络八股

虽然Pytorch在论文中使用较多&#xff0c;但是像Alphafold在蛋白质结构预测的模型&#xff0c;仍然是用Tensorflow写成&#xff0c;遂近期在学其中的语法。 本系列来自慕课北大软微曹健老师的Tensorflow笔记&#xff0c;摘选其中重要部分。 1.导包 2.定义训练集测试集和数据…

专题1 - 双指针 - leetcode 15. 三数之和 - 中等难度

leetcode 15. 三数之和 - 点击直达 leetcode 15. 三数之和 中等难度 双指针1. 题目详情1. 原题链接2. 基础框架 2. 解题思路1. 题目分析2. 算法原理3. 时间复杂度 3. 代码实现4. 知识与收获 leetcode 15. 三数之和 中等难度 双指针 1. 题目详情 给你一个整数数组 nums &#…

代码第二十四天-寻找旋转排序数组中的最小值Ⅱ

寻找旋转排序数组中的最小值Ⅱ 题目要求 解题思路 二分法 当遇到两个left、right两个位置值相同时候&#xff0c;可以选择将 right right-1 代码 class Solution:def findMin(self, nums: List[int]) -> int:left,right0,len(nums)-1while left<right:mid(leftright…

Python编程作业五:面向对象编程

目录 一、类的定义和方法 二、图书管理系统 一、类的定义和方法 定义一个学生类&#xff08;Student&#xff09;&#xff0c;包括学号(id)、姓名(name)、出生日期(birthday)和分数(score)4个属性&#xff0c;其中出生日期是私有属性&#xff0c;不能被外界直接访问。该类应具…

华容道问题求解_详细设计(三)之查找算法1_DFS

&#xff08;续上篇&#xff09; 使用DFS查找算法的原因是因为它符合本人的思考习惯&#xff0c;另外在第一版时用的就是这个方法&#xff0c;后来知道这不是查找这类问题的最好方法。 在前面的概要设计中的框图里描述的方法就是DFS&#xff0c;它可以找到一个解法&#xff0c;…

某省内存取证真题详解

需要环境的私我 题目描述: 一,从内存中获取到用户admin的密码并且破解密码,以Flag{admin,password}形式提交(密码为6位) 二,获取当前系统ip地址及主机名,以Flag{ip:主机名}形式提交; 三,当前系统中存在的挖矿进程,请获取指向的矿池地址,以Flag{ip}形式提交 四,恶意进…

大数据冷热分离方案

数据冷热分离方案 1、背景 ​ 随着业务的发展&#xff0c;在线表中的数据会逐渐增加。常规业务都有冷热数据现象明显的特性&#xff08;需要访问的都是近期产生的热数据&#xff1b;时间久远的冷数据出于备份、备案溯源等诉求会进行在线保留&#xff09;。在业务表数据 量可控…