《设计模式的艺术》笔记 - 观察者模式

介绍

        观察者模式定义对象之间的一种一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象皆得到通知并被自动更新。

实现

myclass.h

//
// Created by yuwp on 2024/1/12.
//#ifndef DESIGNPATTERNS_MYCLASS_H
#define DESIGNPATTERNS_MYCLASS_H#include <iostream>
#include <unordered_map>
#include <atomic>
#include <vector>
#include <memory>class Observer {    // 抽象观察者
public:Observer(const std::string &name);virtual void update() = 0;protected:std::string m_name;
};class Subject { // 目标,提供增加、删除观察者对象方法和通知方法notify
public:virtual void addObserver(Observer *ob);virtual void removeObserver(Observer *ob);virtual void notify();protected:std::vector<Observer *> m_obs;
};class ConcreteObserver : public Observer {  // 具体观察者
public:ConcreteObserver(const std::string &name);void update() override;
};class ConcreteSubject : public Subject {    // 具体目标
public:};#endif //DESIGNPATTERNS_MYCLASS_H

myclass.cpp

//
// Created by yuwp on 2024/1/12.
//#include "myclass.h"
#include <thread>
#include <unistd.h>
#include <sstream>Observer::Observer(const std::string &name) {m_name = name;
}void Subject::addObserver(Observer *ob) {if (ob) {m_obs.push_back(ob);}
}void Subject::removeObserver(Observer *ob) {for (auto it = m_obs.begin(); it != m_obs.end(); ++it) {if (*it == ob) {m_obs.erase(it);}}
}void Subject::notify() {for (auto o : m_obs) {o->update();}
}ConcreteObserver::ConcreteObserver(const std::string &name) : Observer(name) {
}void ConcreteObserver::update() {std::cout << m_name << "观察到目标有变化" << std::endl;
}

main.cpp

#include <iostream>
#include <mutex>
#include "myclass.h"int main() {Observer *ob1 = new ConcreteObserver("观察者1");Observer *ob2 = new ConcreteObserver("观察者2");Observer *ob3 = new ConcreteObserver("观察者3");Subject *sub = new ConcreteSubject();sub->addObserver(ob1);sub->addObserver(ob2);sub->addObserver(ob3);sub->notify();std::cout << "---------------" << std::endl;sub->removeObserver(ob2);sub->notify();delete sub;delete ob1;delete ob2;delete ob3;return 0;
}

总结

优点

        1. 观察者模式可以实现表示层和数据逻辑层的分离。它定义了稳定的消息更新传递机制,并抽象了更新接口,使得可以有各种各样不同的表示层充当具体观察者角色。

        2. 观察者模式在观察目标和观察者之间建立一个抽象的耦合。观察目标只需要维持一个抽象观察者的集合,无须了解其具体观察者。由于观察目标和观察者没有紧密地耦合在一起,因此它们可以属于不同的抽象化层次。

        3. 观察者模式支持广播通信。观察目标会向所有已注册的观察者对象发送通知,简化了一对多系统设计的难度。

        4. 观察者模式满足开闭原则的要求,增加新的具体观察者无须修改原有系统代码。在具体观察者与观察目标之间不存在关联关系的情况下,增加新的观察目标也很方便。

缺点

        1. 如果一个观察目标对象有很多直接和间接观察者,将所有的观察者都通知到会花费很多时间。

        2. 如果在观察者和观察目标之间存在循环依赖,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。

        3. 观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。

适用场景

        1. 一个抽象模型有两个方面,其中一个方面依赖于另一个方面,将这两个方面封装在独立的对象中使它们可以各自独立地改变和复用。

        2. 一个对象的改变将导致一个或多个其他对象也发生改变,而并不知道具体有多少对象将发生改变,也不知道这些对象是谁。

        3. 需要在系统中创建一个触发链,A对象的行为将影响B对象,B对象的行为将影响C对象……可以使用观察者模式创建一种链式触发机制。

练习

myclass.h

//
// Created by yuwp on 2024/1/12.
//#ifndef DESIGNPATTERNS_MYCLASS_H
#define DESIGNPATTERNS_MYCLASS_H#include <iostream>
#include <unordered_map>
#include <atomic>
#include <vector>
#include <memory>class Observer {    // 抽象观察者
public:Observer(const std::string &name);virtual void showMsg(const std::string &msg) = 0;protected:std::string m_name;
};class Subject { // 目标,提供增加、删除观察者对象方法和通知方法notify
public:virtual void addObserver(Observer *ob, float price);virtual void removeObserver(Observer *ob);virtual void notify();protected:std::unordered_map<Observer *, float> m_obs;
};class Investor : public Observer {  // 具体观察者
public:Investor(const std::string &name);void showMsg(const std::string &msg) override;private:};class Stock : public Subject {    // 具体目标
public:Stock();void notify() override;void setPrice(float price);private:float m_price;
};#endif //DESIGNPATTERNS_MYCLASS_H

myclass.cpp

//
// Created by yuwp on 2024/1/12.
//#include "myclass.h"
#include <thread>
#include <unistd.h>
#include <sstream>Observer::Observer(const std::string &name) {m_name = name;
}void Subject::addObserver(Observer *ob, float price) {m_obs[ob] = price;
}void Subject::removeObserver(Observer *ob) {auto it = m_obs.find(ob);if (it != m_obs.end()) {m_obs.erase(it);}
}void Subject::notify() {}Investor::Investor(const std::string &name) : Observer(name) {}void Investor::showMsg(const std::string &msg) {std::cout << m_name << "收到消息: " << msg << std::endl;
}Stock::Stock() {m_price = 100.0;
}void Stock::notify() {for (auto &o : m_obs) {if (std::abs(m_price - o.second) * 20 >= o.second) {    // 价格变化超过5%o.first->showMsg("投资者您好!您购买的股票价格变动超过5%!");}}
}void Stock::setPrice(float price) {if (m_price - price <= 0.000001 && m_price - price >= -0.000001) {return;}m_price = price;notify();
}

main.cpp

#include <iostream>
#include <mutex>
#include "myclass.h"int main() {Observer *ob1 = new Investor("股民1");Observer *ob2 = new Investor("股民2");Stock *stock = new Stock();stock->addObserver(ob1, 99);stock->addObserver(ob2, 100);stock->setPrice(104);std::cout << "------------------" << std::endl;stock->setPrice(105);return 0;
}

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

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

相关文章

Oracle Linux 6.10 安装图解

风险告知 本人及本篇博文不为任何人及任何行为的任何风险承担责任&#xff0c;图解仅供参考&#xff0c;请悉知&#xff01;本次安装图解是在一个全新的演示环境下进行的&#xff0c;演示环境中没有任何有价值的数据&#xff0c;但这并不代表摆在你面前的环境也是如此。生产环境…

ZK高可用架构涉及常用功能整理

ZK高可用架构涉及常用功能整理 1. zk的高可用系统架构和相关组件1.1 Quorum机制1.2 ZAB协议 2. zk的核心参数2.1 常规配置2.2 特殊优化配置 3. zk常用命令3.1 常用基础命令3.2 常用运维命令 4. 事务性4.1 数据写流程4.2 数据读流程 5. 疑问和思考5.1 zk不擅长处理哪些场景&…

gitlab runner 安装、注册、配置、使用

天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物。 每个人都有惰性&#xff0c;但不断学习是好好生活的根本&#xff0c;共勉&#xff01; 文章均为学习整理笔记&#xff0c;分享记录为主&#xff0c;如有错误请指正&#xff0c;共同学习进步。…

「一本通 3.6 例 1」分离的路径

题目描述 为了从 F F F 个草场中的一个走到另一个&#xff0c;贝茜和她的同伴们不得不路过一些她们讨厌的可怕的树。奶牛们已经厌倦了被迫走某一条路&#xff0c;所以她们想建一些新路&#xff0c;使每一对草场之间都会至少有两条相互分离的路径&#xff0c;这样她们就有多一…

vue常用指令(v-show)

一、v-show 指令 作用: 根据真假值,切换元素的显示状态 二、代码演示 1、v-show 绑定判断条件后&#xff0c;根据布尔值决定是否显示图片 不显示图片 代码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><…

骨传导是哪个意思?骨传导的应用领域在哪

很多人都问我骨传导是哪个意思&#xff1f;骨传导的应用领域在哪&#xff1f;我们都知道声音能够在固体、液体、空气三种介质中传播。通常情况下&#xff0c;声音进入我们内耳的方式主要有两种&#xff1a;空气传导和骨传导&#xff0c;骨传导也就是通过固体传导。我们比较熟悉…

深度学习——pycharm远程连接

目录 远程环境配置本地环境配置&#xff08;注意看假设&#xff01;&#xff01;!这是很多博客里没写的&#xff09;步骤1步骤2步骤2.1 配置Connection步骤2.2 配置Mappings 步骤3 配置本地项目的远程解释器技巧1 pycharm中远程终端连接技巧2 远程目录技巧3 上传代码文件技巧4 …

2024.1.23力扣每日一题——最长交替子数组

2024.1.23 题目来源我的题解方法一 枚举 题目来源 力扣每日一题&#xff1b;题序&#xff1a;2765 我的题解 方法一 枚举 每次都以两个相邻作为满足要求的循环数据&#xff0c;并且以一个布尔变量控制循环的位置 时间复杂度&#xff1a;O(n) 空间复杂度&#xff1a;O(1) pub…

【图像拼接】论文精读:Eliminating Structure and Intensity Misalignment in Image Stitching

第一次来请先看这篇文章:【图像拼接(Image Stitching)】关于【图像拼接论文精读】专栏的相关说明,包含专栏使用说明、创新思路分享等(不定期更新) 图像拼接系列相关论文精读 Seam Carving for Content-Aware Image ResizingAs-Rigid-As-Possible Shape ManipulationAdap…

自锁设计更稳固,同为科技(TOWE)服务器电脑IEC 60320电源线

说起IEC 60320标准电源线&#xff0c;可能很多人不知道具体是什么东西&#xff0c;但要说到台式电脑电源线&#xff0c;那大家就都能耳熟能详了。IEC 60320电源线的用途十分广泛&#xff0c;包括家用电器、医疗设备、数据中心服务器、商业机械设备、自动化生产线等都是用此类电…

API网关-Apinto压缩包方式自动化安装配置教程

文章目录 前言一、Apinto安装教程1. 复制脚本2. 增加执行权限3. 执行脚本4. Apinto命令4.1 启动Apinto4.2 停止Apinto4.3 重启Apinto4.4 查看Apinto版本信息4.5 加入Apinto集群4.6 离开Apinto集群4.7 查看Apinto节点信息 5. 卸载Apinto 二、Apserver(Apinto Dashboard V3)安装教…

将文件以指定格式存储~BMP~C的实现~FAT32格式

参考&#xff1a; BMP文件学习笔记&#xff08;一&#xff09;&#xff1a; C/C语言实现.bmp文件读写_c 写入bmp-CSDN博客 U盘到底用什么格式好&#xff1f;FAT32、NTFS还是exFAT&#xff1f; - 知乎 (zhihu.com) 第一部分&#xff1a; 位图文件头 BITMAPFILEHEADER&#x…

力扣1027. 最长等差数列

动态规划 思路&#xff1a; 可以参考力扣1218. 最长定差子序列目前不清楚公差&#xff0c;可以将序列最大最小值找到&#xff0c;公差的范围是 [-(max - min), (max - min)]&#xff0c;按公差递增迭代遍历求出最长等差数列&#xff1b; class Solution { public:int longest…

Mybatis-SqlSessionFactory/多数据源

下面的代码演示了发送一个HTTP请求到Controller&#xff0c;如果key“dev”&#xff0c;则查询dev数据库&#xff0c;否则查询默认的数据库 Resourceprivate SqlSessionFactory sqlSessionFactory;Resourceprivate DataSource defaultDataSource;Resourceprivate XXXMapper xxx…

go语言下划线、变量和常量

1、下划线 “_”是特殊标识符&#xff0c;用来忽略结果。 1.1. 下划线在import中 在Golang里&#xff0c;import的作用是导入其他package。import 下划线&#xff08;如&#xff1a;import hello/imp&#xff09;的作用&#xff1a;当导入一个包时&#xff0c;该包下的文件里…

IDEA 创建maven项目没有src

环境&#xff1a; IntelliJ IDEA 2022.3.3 (Ultimate Edition) JDK 17 Windows 11 10.0 Maven 3.9.5 创建maven项目的时候没有src目录 试过网上说的重新配置maven库&#xff0c;增加vm-options&#xff0c;并没有什么用。直到我看见了 正常创建就好了。

[计算机提升] 清理系统盘的前期准备

5.1 清理系统盘的前期准备 5.1.1 系统盘之殇&#xff1a;为什么系统盘会越来越大 在windows系统中&#xff0c;系统盘一般是C盘&#xff0c;随着电脑使用时间变长&#xff0c;系统盘会变得越来越大。而系统盘通常在安装系统时已经固定好了&#xff0c;如果系统盘的剩余空间太…

【前端基础--1】

为后面爬虫打基础 使用Visual Studio Code&#xff08;VS Code&#xff09; https://code.visualstudio.com/#alt-downloads 网页基础 创建一个html网页 新建一个文件 文件名后缀.html 书写网页模板 html:5 回车键&#xff08;或者Tab键&#xff09;英文感叹号! 回…

接收邮件触发器

无代码自动化-接收邮件触发器-做的最好的是make.com。数环通和集简云在这方面差了很多&#xff0c;我考虑主要原因应该是国内没有用邮件的习惯&#xff0c;都是微信来微信去。 2024年1月25日的观察结果 集简云 有邮件触发器&#xff0c;但是它获取的邮件信息很少。 我最关心…

深入解析MySQL数据库锁机制

目录 引言 一、锁的基本概念 1. 共享锁和排它锁 2. 行锁和表锁 二、MySQL锁的类型 1. 共享锁&#xff08;Shared Lock&#xff09; 2. 排它锁&#xff08;Exclusive Lock&#xff09; 3. 意向共享锁&#xff08;Intention Shared Lock&#xff09; 4. 意向排它锁&…