设计模式(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;
}

 运行结果:

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

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

相关文章

模型量化 | Pytorch的模型量化基础

官方网站&#xff1a;Quantization — PyTorch 2.1 documentation Practical Quantization in PyTorch | PyTorch 量化简介 量化是指执行计算和存储的技术 位宽低于浮点精度的张量。量化模型 在张量上执行部分或全部操作&#xff0c;精度降低&#xff0c;而不是 全精度&#xf…

HTML+CSS制作动漫绿巨人

🎀效果展示 🎀代码展示 <!DOCTYPE html> <html lang="en" > <head>

Apollo自动驾驶概述:引领智能交通的未来(文末赠送apollo周边)

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏:《linux深造日志》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! ⛳️ 粉丝福利活动 ✅参与方式&#xff1a;通过连接报名观看课程&#xff0c;即可免费获取精美周边 ⛳️活动链接&#xf…

算法基础之最短编辑距离

最短编辑距离 核心思想 &#xff1a; 线性dp 集合定义 &#xff1a; f[i][j]为操作方式的最小值 集合计算 : 三种操作 取最小 ① 删除 : 将a[i]删掉 使ab相同 –> f[i-1][j] 1 f[i][j]② 增添 : 在a[i]后加上一个数 使ab相同 –> f[i][j-1] 1 f[i][j]③ 替换 : 将a[…

聚观早报 |一加Ace 3外观细节;小米14 Ultra电池曝光

聚观早报每日整理最值得关注的行业重点事件&#xff0c;帮助大家及时了解最新行业动态&#xff0c;每日读报&#xff0c;就读聚观365资讯简报。 整理丨Cutie 12月28日消息 一加Ace 3外观细节 小米14 Ultra电池曝光 Lucid正开发电动汽车 英特尔获以色列32亿美元补贴 新能…

用编程解决习题【计算机图像处理】

用编程解决习题【计算机图像处理】 前言版权第三章 03采样量化与像素间关系三种距离计算编程 第六章 06图像的直方图变换均衡化直方图编程规定化直方图编程 第七章 07图像的噪声抑制均值滤波 中值滤波计算编程knn滤波计算编程 第十章 10二值图像的分析贴标签 膨胀 腐蚀编程 最后…

Hadoop安装笔记_单机/伪分布式配置_Hadoop3.1.3——备赛笔记——2024全国职业院校技能大赛“大数据应用开发”赛项——任务2:离线数据处理

将下发的ds_db01.sql数据库文件放置mysql中 12、编写Scala代码&#xff0c;使用Spark将MySQL的ds_db01库中表user_info的全量数据抽取到Hive的ods库中表user_info。字段名称、类型不变&#xff0c;同时添加静态分区&#xff0c;分区字段为etl_date&#xff0c;类型为String&am…

代码审计必要性探讨

1、背景 为了保证代码的质量&#xff0c;需要一系列的流程来进行保证&#xff1a; 今天要探讨的是代码审计的必要性。 2、代码审计 代码审计的做法多种多样&#xff0c;我理解必须解决以下问题 &#xff0c;才可能有效&#xff1a; 核心&#xff1a;审计的本质是对比&#…

RabbitMQ 报错:Failed to declare queue(s):[QD, QA, QB]

实在没想到会犯这种低级错误。 回顾整理一下吧&#xff1a; 原因&#xff1a;SpringBoot主配置类默认只会扫描自己所在的包及其子包下面的组件。其他位置的配置不会被扫描。 如果非要使用其他位置&#xff0c;就需要在启动类上面指定新的扫描位置。注意新的扫描位置会覆盖默…

C# 运算符重载

C# 运算符重载 运算符重载运算符重载的实现1. 类中重载的方法必须是public公有的2. 类中定义的重载方法必须是静态的3. 在运算符前需要加上关键字 operator 使用如下可重载和不可重载运算符实例 运算符重载 一提到 - * / %这种类似的运算符都应该很清楚是什么&#xff0c;但是…

Unity网格篇Mesh(二)

Unity网格篇Mesh&#xff08;二&#xff09; 介绍4.生成额外的顶点数据未计算法线计算法线没有法线vs有法线错误的UV坐标Clamping vs warpping正确的UV纹理&#xff0c;平铺&#xff08;1,1&#xff09; vs 平铺&#xff08;2,1&#xff09;凹凸不平的表面&#xff0c;产生了金…

【Java 中锁的种类】

文章目录 一、公平锁和非公平锁二、可重入锁&#xff08;递归锁&#xff09;三、自旋锁四、独占锁(写锁)/共享锁(读锁)/互斥锁 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 一、公平锁和非公平锁 遵守先来后到的是公平锁&#xff0c;不遵守的是非公…

Mysql主从同步原理

文章目录 前言同步原理复制的核心流程写在最后 前言 随着社会的进步大家对服务端应用程序的性能指标有着越来越高的要求&#xff0c;比如响应时间、吞吐率、QPS、TPS等等。基本上大多数系统都会要求响应时间不超过3s&#xff0c;当然对吞吐量和并发量也会根据具体的业务场景进…

C#编程艺术:Fizzler库助您高效爬取www.twitter.com音频

数据是当今数字时代的核心资源&#xff0c;但是从互联网上抓取数据并不容易。本文将教您如何利用C#编程艺术和Fizzler库高效爬取Twitter上的音频数据&#xff0c;让您轻松获取所需信息。 Twitter简介 Twitter是全球最大的社交媒体平台之一&#xff0c;包含丰富的音频资源。用…

Android原生实现分段选择

六年前写的一个控件&#xff0c;一直没有时间总结&#xff0c;趁年底不怎么忙&#xff0c;整理一下之前写过的组件。供大家一起参考学习。废话不多说&#xff0c;先上图。 一、效果图 实现思路使用的是radioGroup加radiobutton组合方式。原理就是通过修改RadioButton 的backgr…

初始JVM

目录 一、什么是JVM 二、JVM与字节码 三、Java程序运行机制 四、JVM 的主要组成部分及其作用 一、什么是JVM JVM 本质上是一个运行在计算机上的程序&#xff0c;他的职责是运行Java字节码文件 二、JVM与字节码 三、Java程序运行机制 首先利用IDE集成开发工具编写Java源代码…

Docker 部署RAP2

1、Github介绍 https://github.com/thx/rap2-delos 2、安装Docker环境 yum install -y yum-utils device-mapper-persistent-data lvm2 yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo yum install -y docker-ce systemctl enable…

环形链表、环形链表 II、有效的括号​​​​​​​(leetcode)

目录 一、环形链表 方法&#xff08;快慢指针&#xff09;&#xff1a; 二、环形链表 II 三、有效的括号 一、环形链表 给你一个链表的头节点 head &#xff0c;判断链表中是否有环。 如果链表中有某个节点&#xff0c;可以通过连续跟踪 next 指针再次到达&#xff0c;则链…

C# 图标标注小工具-查看重复文件

目录 效果 项目 代码 下载 效果 项目 代码 using System; using System.Collections.Generic; using System.Data; using System.IO; using System.Linq; using System.Security.Cryptography; using System.Windows.Forms;namespace ImageDuplicate {public partial clas…

SparkSQL 执行底层原理解析

从Spark SQL 底层架构可以看到&#xff0c;我们写的SQL语句&#xff0c;经过一个优化器&#xff08;Catalyst&#xff09;处理&#xff0c;转化为可执行的RDD&#xff0c;提交给集群执行。 SQL到RDD中间经过了一个Catalyst&#xff0c;它便是Spark SQL的核心&#xff0c;是针对…