当前位置: 首页 > 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 ( …...

使用VSCode开发Django指南

使用VSCode开发Django指南 一、概述 Django 是一个高级 Python 框架&#xff0c;专为快速、安全和可扩展的 Web 开发而设计。Django 包含对 URL 路由、页面模板和数据处理的丰富支持。 本文将创建一个简单的 Django 应用&#xff0c;其中包含三个使用通用基本模板的页面。在此…...

docker详细操作--未完待续

docker介绍 docker官网: Docker&#xff1a;加速容器应用程序开发 harbor官网&#xff1a;Harbor - Harbor 中文 使用docker加速器: Docker镜像极速下载服务 - 毫秒镜像 是什么 Docker 是一种开源的容器化平台&#xff0c;用于将应用程序及其依赖项&#xff08;如库、运行时环…...

golang循环变量捕获问题​​

在 Go 语言中&#xff0c;当在循环中启动协程&#xff08;goroutine&#xff09;时&#xff0c;如果在协程闭包中直接引用循环变量&#xff0c;可能会遇到一个常见的陷阱 - ​​循环变量捕获问题​​。让我详细解释一下&#xff1a; 问题背景 看这个代码片段&#xff1a; fo…...

django filter 统计数量 按属性去重

在Django中&#xff0c;如果你想要根据某个属性对查询集进行去重并统计数量&#xff0c;你可以使用values()方法配合annotate()方法来实现。这里有两种常见的方法来完成这个需求&#xff1a; 方法1&#xff1a;使用annotate()和Count 假设你有一个模型Item&#xff0c;并且你想…...

(转)什么是DockerCompose?它有什么作用?

一、什么是DockerCompose? DockerCompose可以基于Compose文件帮我们快速的部署分布式应用&#xff0c;而无需手动一个个创建和运行容器。 Compose文件是一个文本文件&#xff0c;通过指令定义集群中的每个容器如何运行。 DockerCompose就是把DockerFile转换成指令去运行。 …...

如何在最短时间内提升打ctf(web)的水平?

刚刚刷完2遍 bugku 的 web 题&#xff0c;前来答题。 每个人对刷题理解是不同&#xff0c;有的人是看了writeup就等于刷了&#xff0c;有的人是收藏了writeup就等于刷了&#xff0c;有的人是跟着writeup做了一遍就等于刷了&#xff0c;还有的人是独立思考做了一遍就等于刷了。…...

如何理解 IP 数据报中的 TTL?

目录 前言理解 前言 面试灵魂一问&#xff1a;说说对 IP 数据报中 TTL 的理解&#xff1f;我们都知道&#xff0c;IP 数据报由首部和数据两部分组成&#xff0c;首部又分为两部分&#xff1a;固定部分和可变部分&#xff0c;共占 20 字节&#xff0c;而即将讨论的 TTL 就位于首…...

今日学习:Spring线程池|并发修改异常|链路丢失|登录续期|VIP过期策略|数值类缓存

文章目录 优雅版线程池ThreadPoolTaskExecutor和ThreadPoolTaskExecutor的装饰器并发修改异常并发修改异常简介实现机制设计原因及意义 使用线程池造成的链路丢失问题线程池导致的链路丢失问题发生原因 常见解决方法更好的解决方法设计精妙之处 登录续期登录续期常见实现方式特…...

Mobile ALOHA全身模仿学习

一、题目 Mobile ALOHA&#xff1a;通过低成本全身远程操作学习双手移动操作 传统模仿学习&#xff08;Imitation Learning&#xff09;缺点&#xff1a;聚焦与桌面操作&#xff0c;缺乏通用任务所需的移动性和灵活性 本论文优点&#xff1a;&#xff08;1&#xff09;在ALOHA…...

[论文阅读]TrustRAG: Enhancing Robustness and Trustworthiness in RAG

TrustRAG: Enhancing Robustness and Trustworthiness in RAG [2501.00879] TrustRAG: Enhancing Robustness and Trustworthiness in Retrieval-Augmented Generation 代码&#xff1a;HuichiZhou/TrustRAG: Code for "TrustRAG: Enhancing Robustness and Trustworthin…...