当前位置: 首页 > news >正文

设计模式(4)--对象行为(7)--观察者

1. 意图

     定义对象间的一种一对多的依赖关系,

     当一个对象的状态改变时,所有依赖于它的对象都得到通知并被自动更新。

2. 四种角色

     抽象目标(Subject)、具体目标(Concrete Subject)、抽象观察者(Observer)、

     具体观察者(Concrete Observer)

3. 优点

    3.1 目标和观察者之间的耦合是抽象的。

    3.2 支持广播通信。

4. 缺点

    4.1 可能导致意外的更新。

5. 相关模式

     当目标和观察者间的依赖关系特别复杂时,需要一个维护这些关系的对象,

     这样的对象称为ChangeMananger。

     5.1 ChangeManager可使用单例模式来保证它是唯一的并且是可全局访问的。

     5.2 ChangeManager充当目标和观察者之间的Mediator

6. 代码示意(C++)
#pragma once
#include <string>
#include <iostream>
#include <vector>
using namespace std;class Subject;class Observer
{
public:virtual void Update(Subject* pSubject) = 0;
protected:Observer() {}
};
class ConcreteObserver :public Observer
{string m_state;string m_name;
public:ConcreteObserver(const string& name) :m_name(name) {}virtual void Update(Subject* pSubject);
};class Subject
{vector<Observer*> m_observers;
public:virtual string GetState() = 0;virtual void SetState(const string& state) = 0;
public:void Attach(Observer* pObserver) {m_observers.emplace_back(pObserver);cout << "After attached, observers size is:" << m_observers.size() << endl;}void Detach(Observer* pObserver) {m_observers.erase(std::remove_if(m_observers.begin(), m_observers.end(), [&](Observer* p) { return p == pObserver; }), m_observers.end());cout << "After detached, observers size is:" << m_observers.size() << endl;}void Notify(){auto it = m_observers.begin();while (it != m_observers.end()) {(*it)->Update(this);++it;}}
protected:Subject(){}
};
class ConcreteSubject :public Subject
{string m_state;
public:virtual string GetState() {return m_state;}virtual void SetState(const string& state) {m_state = state;}
};

Observer.cpp:

#include "Observer.h"void ConcreteObserver::Update(Subject* pSubject) {m_state = pSubject->GetState();cout << "Observer:" << m_name << ",got state from subject:" << m_state << endl;
}
#include "Observer.h"
int main() {Subject* pSubject = new ConcreteSubject();Observer* pObserver1 = new ConcreteObserver("obs1");Observer* pObserver2 = new ConcreteObserver("obs2");pSubject->Attach(pObserver1);pSubject->Attach(pObserver2);pSubject->SetState("hello1");pSubject->Notify();pSubject->Detach(pObserver1);pSubject->SetState("hello2");pSubject->Notify();delete pObserver2;delete pObserver1;delete pSubject;return 0;
}

运行结果:

   6.1 目标和观察者之间只知道彼此的抽象类(3.1)。

   6.2  Subject::Notify里的循环就是广播,观察者自己决定是否处理某一通知(3.2)。

   6.3 使用ChangeMananger会使代码复杂些,但简化了Subject,且使更新策略更加灵活。

使用ChangeMananger代码示意:

#pragma once
#include <string>
#include <iostream>
#include <vector>
#include <map>
using namespace std;class Subject;class Observer
{
public:virtual void Update(Subject* pSubject) = 0;virtual string GetName() = 0;
protected:Observer() {}
};
class ConcreteObserver :public Observer
{string m_state;string m_name;
public:ConcreteObserver(const string& name) :m_name(name) {}virtual string GetName() { return m_name; }virtual void Update(Subject* pSubject);
};class ChangeManager;
class SimpleChangeManager;class Subject
{ChangeManager* m_pChangeManager;
public:virtual string GetState() = 0;virtual void SetState(const string& state) = 0;virtual ~Subject();
public:void Attach(Observer* pObserver);void Detach(Observer* pObserver);void Notify();
protected:Subject();
};
class ConcreteSubject :public Subject
{string m_state;
public:ConcreteSubject() {}virtual string GetState() {return m_state;}virtual void SetState(const string& state) {m_state = state;}
};class ChangeManager
{
public:virtual void Register(Subject* pSubject, Observer* pObserver) = 0;virtual void Unregister(Subject* pSubject, Observer* pObserver) = 0;virtual void Notify() = 0;
protected:ChangeManager() {}
};class SimpleChangeManager :public ChangeManager
{map<Subject*, vector<Observer*> > m_mapSubjects;
private:static SimpleChangeManager* s_instance;
public:static ChangeManager* Instance() {if (0 == s_instance) {s_instance = new SimpleChangeManager();}return s_instance;}static void DelInstance() {delete s_instance;s_instance = 0;}
public:virtual void Register(Subject* pSubject, Observer* pObserver) {vector<Observer*>& observers = m_mapSubjects[pSubject];auto it = find(observers.begin(), observers.end(), pObserver);if (it == observers.end()) {observers.emplace_back(pObserver);cout << pObserver->GetName() << " is registered successful" << endl;}else {cout << pObserver->GetName() << " is already registered" << endl;}}virtual void Unregister(Subject* pSubject, Observer* pObserver) {auto it = m_mapSubjects.find(pSubject);if (it == m_mapSubjects.end()) {cout << "No need unregister in map for:" << pObserver->GetName() << endl;}else {vector<Observer*>& observers = m_mapSubjects[pSubject];auto itRemove = remove_if(observers.begin(), observers.end(), [&](Observer* p) { return p == pObserver; });if (itRemove == observers.end()) {cout << "No need unregister in vector for:" << pObserver->GetName() << endl;}else {observers.erase(itRemove, observers.end());cout << pObserver->GetName() << " is unregistered successful" << endl;if (observers.size() == 0) {m_mapSubjects.erase(pSubject);}}}}virtual void Notify() {for (auto& pair : m_mapSubjects) {vector<Observer*>& observers = pair.second;auto it = observers.begin();while (it != observers.end()) {(*it)->Update(pair.first);++it;}}}
protected:SimpleChangeManager() {}
};

 Observer.cpp:

#include "Observer.h"void ConcreteObserver::Update(Subject* pSubject) {m_state = pSubject->GetState();cout << "Observer:" << m_name << ",got state from subject:" << m_state << endl;
}Subject::Subject() {m_pChangeManager = SimpleChangeManager::Instance();
}
Subject::~Subject() {m_pChangeManager = 0;SimpleChangeManager::DelInstance();
}
void Subject::Attach(Observer* pObserver) {m_pChangeManager->Register(this, pObserver);
}
void Subject::Detach(Observer* pObserver) {m_pChangeManager->Unregister(this, pObserver);
}
void Subject::Notify()
{m_pChangeManager->Notify();
}SimpleChangeManager* SimpleChangeManager::s_instance = 0;
#include "Observer.h"
int main() {Subject* pSubject = new ConcreteSubject();Observer* pObserver1 = new ConcreteObserver("obs1");Observer* pObserver2 = new ConcreteObserver("obs2");pSubject->Attach(pObserver1);pSubject->Attach(pObserver2);pSubject->Attach(pObserver1);pSubject->SetState("hello1");pSubject->Notify();pSubject->Detach(pObserver1);pSubject->Detach(pObserver1);pSubject->SetState("hello2");pSubject->Notify();pSubject->Detach(pObserver2);pSubject->Detach(pObserver2);delete pObserver2;delete pObserver1;delete pSubject;return 0;
}

 运行结果:

相关文章:

设计模式(4)--对象行为(7)--观察者

1. 意图 定义对象间的一种一对多的依赖关系&#xff0c; 当一个对象的状态改变时&#xff0c;所有依赖于它的对象都得到通知并被自动更新。 2. 四种角色 抽象目标(Subject)、具体目标(Concrete Subject)、抽象观察者(Observer)、 具体观察者(Concrete Observer) 3. 优点 3.1 …...

MySQL所有常见问题

一、事务 定义:一组操作要么全部成功,要么全部失败,目的是为了保证数据最终的一致性 在MySQL中,提供了一系列事务相关的命令: start transaction | begin | begin work:开启一个事务commit:提交一个事务rollback:回滚一个事务事务的ACID 原子性(Atomicity):当前事…...

锐捷交换机配置 SNMP

配置步骤 ( SNMP v2 ) 步骤一 -- 创建共同体(Community) ruijie(config)#snmp-server community test rw # rw 为读和写口令ruijie(config)#snmp-server community public ro # ro 为只读和写口令这里的共同体为“test”,通常只读口令和读写口令单独配置,提升安…...

Windows 10 安装和开启VNCServer 服务

Windows 10 安装和开启VNCServer 服务 登录云服务器 使用本地RDP登录到配置VNCServer服务的Windows10系统的云服务器。 下载VNC Server安装包 打开官网下载VNCServer安装包 URL&#xff1a;https://www.realvnc.com/en/connect/download/vnc/windows/ 安装VNC Server 双击…...

js遍历后端返回的集合将条件相同的放入同一个数组内

项目场景&#xff1a; echarts折线图需要根据条件动态展示多条不同曲线 解决方案&#xff1a; 后端直接将使用sql将数据查询出来返回即可,因为我这里不是Java使用的C#不是很熟练后台不好写逻辑,所以在前端js完成的 代码如下: function createline(villagename, buildingname…...

GcExcel:DsExcel 7.0 for Java Crack

GcExcel:DsExcel 7.0-高速 Java Excel 电子表格 API 库 Document Solutions for Excel&#xff08;DsExcel&#xff0c;以前称为 GcExcel&#xff09;Java 版允许您在 Java 应用程序中以编程方式创建、编辑、导入和导出 Excel 电子表格。几乎可以部署在任何地方。 创建、加载、…...

基于SpringBoot的职业生涯规划系统

文章目录 项目介绍主要功能截图:部分代码展示设计总结项目获取方式🍅 作者主页:超级无敌暴龙战士塔塔开 🍅 简介:Java领域优质创作者🏆、 简历模板、学习资料、面试题库【关注我,都给你】 🍅文末获取源码联系🍅 项目介绍 基于SpringBoot的职业生涯规划系统,java…...

基于Java+SpringBoot+vue+elementui的校园文具商城系统详细设计和实现

基于JavaSpringBootvueelementui的校园文具商城系统详细设计和实现 欢迎点赞 收藏 ⭐留言 文末获取源码联系方式 文章目录 基于JavaSpringBootvueelementui的校园文具商城系统详细设计和实现前言介绍&#xff1a;系统设计&#xff1a;系统开发流程用户登录流程系统操作流程 功能…...

PyTorch中常用的工具(5)使用GPU加速:CUDA

文章目录 前言4 使用GPU加速&#xff1a;CUDA5 小结 前言 在训练神经网络的过程中需要用到很多的工具&#xff0c;最重要的是数据处理、可视化和GPU加速。本章主要介绍PyTorch在这些方面常用的工具模块&#xff0c;合理使用这些工具可以极大地提高编程效率。 由于内容较多&am…...

Qt+opencv 视频分解为图片

最近遇到一些售前提供的BUG&#xff0c;但是他们提供的是录像视频&#xff0c;因为处理显示速度比较快&#xff0c;因此很难找到出现问题的位置。需要反复播放&#xff0c;自己编写了一个视频分解成图片这样就可以一张图一张图的对比&#xff0c;方便查看。 开发环境 qtopenv…...

一篇文章认识微服务的优缺点和微服务技术栈

目录 1、微服务 2、微服务架构 3、微服务优缺点 3.1 优点 3.2 缺点 4、微服务技术栈 1、微服务 微服务化的核心就是将传统的一站式应用&#xff0c;根据业务拆分成一个一个的服务&#xff0c;彻底地去耦合&#xff0c;每一个微服务提供单个业务功能的服务&#xff0c;一…...

[spark] dataframe的数据导入Mysql5.6

在 Spark 项目中使用 Scala 连接 MySQL 5.6 并将 DataFrame 中的数据保存到 MySQL 中的步骤如下&#xff1a; 添加 MySQL 连接驱动依赖&#xff1a; 在 Spark 项目中&#xff0c;你需要在项目的构建工具中添加 MySQL 连接驱动的依赖。 如果使用 Maven&#xff0c;可以在 pom.xm…...

2023年度业务风险报告:四个新风险趋势

目录 倒票的黄牛愈加疯狂 暴增的恶意网络爬虫 愈加猖獗的羊毛党 层出不穷的新风险 业务风险呈现四个趋势 防御云业务安全情报中心“2023年业务风险数据”统计显示&#xff0c;恶意爬虫风险最多&#xff0c;占总数的37.8%&#xff1b;其次是虚假账号注册&#xff0c;占18.79%&am…...

python编程从入门到实践(1)

文章目录 2.2.1命名的说明2.3字符串2.3.1使用方法修改字符串的大小写2.3.2 在字符串中使用变量2.3.3 制表符 和 换行符2.5.4删除空白2.5.5 删除前缀&#xff0b;后缀 2.2.1命名的说明 只能包含&#xff1a;字母&#xff0c;下划线&#xff0c;数字 必须&#xff1a;字母&#…...

ElasticSearch 文档操作

创建文档 指定id // 无则插入&#xff0c;有则覆盖&#xff08;覆盖的逻辑是先删除&#xff0c;再插入&#xff09; PUT /<target>/_doc/<_id> // 无则插入&#xff0c;有则覆盖 POST /<target>/_doc/<_id> // 无则插入&#xff0c;有则报错 PUT /&l…...

NXOpenC++布尔求和命令

一、概述 在进行批量布尔求和时&#xff0c;采用NXOpenC的方式要比UFun的方式美观的多&#xff0c;个人认为&#xff0c;ufun中UF_MODL_unite_bodies函数采用的是两两进行合并&#xff0c;显示多个步骤&#xff0c;而NXOpenC采用的是一个工具体和多个目标体进行合并&#xff0c…...

ubuntu python播放MP3,wav音频和录音

目录 一.利用pygame&#xff08;略显麻烦&#xff0c;有时候播放不太正常&#xff09;1.安装依赖库2.代码 二.利用mpg123&#xff08;简洁方便&#xff0c;但仅争对mp3&#xff09;1.安装依赖库2.代码 三.利用sox&#xff08;简单方便&#xff0c;支持的文件格式多&#xff09;…...

Rust学习笔记000 安装

安装命令 curl --proto https --tlsv1.2 -sSf https://sh.rustup.rs | sh $ curl --proto https --tlsv1.2 -sSf https://sh.rustup.rs | sh info: downloading installerWelcome to Rust!This will download and install the official compiler for the Rust programming la…...

python AI五子棋对战

我写过一篇c++五子棋 c++五子棋代码-CSDN博客 现在又写了python import copy import time from enum import IntEnum import pygame from pygame.locals import *time = time.strftime("%Y-%m-%d %H:%M:%S") version = str(time)# 基础参数设置 square_size = 40 …...

图文证明 费马,罗尔,拉格朗日,柯西

图文证明 罗尔,拉格朗日,柯西 费马引理和罗尔都比较好证,不过多阐述,看图即可: 费马引理: 罗尔定理: 重点来证明拉格朗日和柯西 拉格朗日: 我认为不需要去看l(x)的那一行更好推: 详细的推理过程: 构造 h ( x ) f ( x ) − l ( x ) , 因为 a , b 两点为交点 , f ( a ) l ( …...

基于uniapp+WebSocket实现聊天对话、消息监听、消息推送、聊天室等功能,多端兼容

基于 ​UniApp + WebSocket​实现多端兼容的实时通讯系统,涵盖WebSocket连接建立、消息收发机制、多端兼容性配置、消息实时监听等功能,适配​微信小程序、H5、Android、iOS等终端 目录 技术选型分析WebSocket协议优势UniApp跨平台特性WebSocket 基础实现连接管理消息收发连接…...

可靠性+灵活性:电力载波技术在楼宇自控中的核心价值

可靠性灵活性&#xff1a;电力载波技术在楼宇自控中的核心价值 在智能楼宇的自动化控制中&#xff0c;电力载波技术&#xff08;PLC&#xff09;凭借其独特的优势&#xff0c;正成为构建高效、稳定、灵活系统的核心解决方案。它利用现有电力线路传输数据&#xff0c;无需额外布…...

Vue2 第一节_Vue2上手_插值表达式{{}}_访问数据和修改数据_Vue开发者工具

文章目录 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染2. 插值表达式{{}}3. 访问数据和修改数据4. vue响应式5. Vue开发者工具--方便调试 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染 准备容器引包创建Vue实例 new Vue()指定配置项 ->渲染数据 准备一个容器,例如: …...

[10-3]软件I2C读写MPU6050 江协科技学习笔记(16个知识点)

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16...

反射获取方法和属性

Java反射获取方法 在Java中&#xff0c;反射&#xff08;Reflection&#xff09;是一种强大的机制&#xff0c;允许程序在运行时访问和操作类的内部属性和方法。通过反射&#xff0c;可以动态地创建对象、调用方法、改变属性值&#xff0c;这在很多Java框架中如Spring和Hiberna…...

ardupilot 开发环境eclipse 中import 缺少C++

目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...

CMake控制VS2022项目文件分组

我们可以通过 CMake 控制源文件的组织结构,使它们在 VS 解决方案资源管理器中以“组”(Filter)的形式进行分类展示。 🎯 目标 通过 CMake 脚本将 .cpp、.h 等源文件分组显示在 Visual Studio 2022 的解决方案资源管理器中。 ✅ 支持的方法汇总(共4种) 方法描述是否推荐…...

微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据

微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据 Power Query 具有大量专门帮助您清理和准备数据以供分析的功能。 您将了解如何简化复杂模型、更改数据类型、重命名对象和透视数据。 您还将了解如何分析列&#xff0c;以便知晓哪些列包含有价值的数据&#xff0c;…...

2025季度云服务器排行榜

在全球云服务器市场&#xff0c;各厂商的排名和地位并非一成不变&#xff0c;而是由其独特的优势、战略布局和市场适应性共同决定的。以下是根据2025年市场趋势&#xff0c;对主要云服务器厂商在排行榜中占据重要位置的原因和优势进行深度分析&#xff1a; 一、全球“三巨头”…...

技术栈RabbitMq的介绍和使用

目录 1. 什么是消息队列&#xff1f;2. 消息队列的优点3. RabbitMQ 消息队列概述4. RabbitMQ 安装5. Exchange 四种类型5.1 direct 精准匹配5.2 fanout 广播5.3 topic 正则匹配 6. RabbitMQ 队列模式6.1 简单队列模式6.2 工作队列模式6.3 发布/订阅模式6.4 路由模式6.5 主题模式…...