行为型设计模式之观察者模式【设计模式系列】

news2024/12/26 11:09:45

系列文章目录

C++技能系列
Linux通信架构系列
C++高性能优化编程系列
深入理解软件架构设计系列
高级C++并发线程编程
设计模式系列

期待你的关注哦!!!
在这里插入图片描述

现在的一切都是为将来的梦想编织翅膀,让梦想在现实中展翅高飞。
Now everything is for the future of dream weaving wings, let the dream fly in reality.

行为型设计模式之观察者模式

  • 系列文章目录
  • 一、观察者模式介绍
  • 二、观察者模式优缺点
    • 2.1 优点
    • 2.2 缺点
  • 三、观察者模式使用场景
  • 四、观察者模式实现
      • 4.1 示例1 - 代码实现
      • 4.1 示例2 - 代码实现

一、观察者模式介绍

⚠️ 意图:
定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。

⚠️ 主要解决:
一个对象状态改变给其他对象通知的问题,而且要考虑到易用和低耦合,保证高度的协作。

⚠️ 何时使用:
一个对象(目标对象)的状态发生改变,所有的依赖对象(观察者对象)都将得到通知,进行广播通知。

⚠️ 如何解决:
使用面向对象技术,可以将这种依赖关系弱化。

观察者模式(Observer),又叫发布-订阅模式(Publish/Subscribe):定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都要得到通知并自动更新。

观察者模式从根本上讲必须包含两个角色:观察者和被观察对象。

被观察对象自身应该包含一个容器来存放观察者对象,当被观察者自身发生改变时通知容器内所有的观察者对象自动更新。

观察者对象可以注册到被观察者的中,完成注册后可以检测被观察者的变化,接收被观察者的通知。当然观察者也可以被注销掉,停止对被观察者的监控。

在这里插入图片描述

图1_1 观察者模式类图

二、观察者模式优缺点

2.1 优点

  • 观察者和被观察者是抽象耦合的。

  • 建立一套触发机制。

2.2 缺点

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

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

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

三、观察者模式使用场景

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

  • 当对一个对象的改变需要同时改变其它对象,而不知道具体有多少对象有待改变;

  • 当一个对象必须通知其它对象,而它又不能假定其它对象是谁;也就是说,你不希望这些对象是紧密耦合的。

四、观察者模式实现

4.1 示例1 - 代码实现

这里的目标 Subject 提供依赖于它的观察者 Observer 的注册( Attach) 和注销( Detach)操作,并且提供了使得依赖于它的所有观察者同步的操作( Notify)。 观察者 Observer 则提供一个 Update 操作, 注意这里的 Observer 的 Update 操作并不在 Observer 改变了 Subject 目标状态的时候就对自己进行更新, 这个更新操作要延迟到 Subject 对象发出 Notify 通知所有Observer 进行修改(调用 Update)。

#include <iostream>
#include <string>
#include <list>
using namespace std;
 
class Subject;
//抽象观察者
class Observer
{
protected:
    string name;
    Subject *sub;
public:
    Observer(string name, Subject *sub)
    {
        this->name = name;
        this->sub = sub;
    }
    virtual void update() = 0;
};
//具体的观察者,看股票的
class StockObserver :public Observer
{
public:
    StockObserver(string name, Subject *sub) :Observer(name, sub)
    {
    }
    void update();
};
//具体的观察者,看NBA的
class NBAObserver :public Observer
{
public:
    NBAObserver(string name, Subject *sub) :Observer(name, sub)
    {
    }
    void update();
};
//抽象通知者
class Subject
{
protected:
    list<Observer*> observers;
public:
    string action;
    virtual void attach(Observer*) = 0;
    virtual void detach(Observer*) = 0;
    virtual void notify() = 0;
};
//具体通知者,秘书
class Secretary :public Subject
{
    void attach(Observer *observer)
    {
        observers.push_back(observer);
    }
    void detach(Observer *observer)
    {
        list<Observer *>::iterator iter = observers.begin();
        while (iter != observers.end())
        {
            if ((*iter) == observer)
            {
                observers.erase(iter);
            }
            ++iter;
        }
    }
    void notify()
    {
        list<Observer *>::iterator iter = observers.begin();
        while (iter != observers.end())
        {
            (*iter)->update();
            ++iter;
        }
    }
};
 
void StockObserver::update()
{
    cout << name << " 收到消息:" << sub->action << endl;
    if (sub->action == "梁所长来了!")
    {
        cout << "我马上关闭股票,装做很认真工作的样子!" << endl;
    }
}
 
void NBAObserver::update()
{
    cout << name << " 收到消息:" << sub->action << endl;
    if (sub->action == "梁所长来了!")
    {
        cout << "我马上关闭NBA,装做很认真工作的样子!" << endl;
    }
}
 
int main()
{
    Subject *dwq = new Secretary(); //创建观察者<br>    //被观察的对象
    Observer *xs = new NBAObserver("xiaoshuai", dwq);
    Observer *zy = new NBAObserver("zouyue", dwq);
    Observer *lm = new StockObserver("limin", dwq);
    //加入观察队列
    dwq->attach(xs);
    dwq->attach(zy);
    dwq->attach(lm);
    //事件
    dwq->action = "去吃饭了!";<br>    //通知
    dwq->notify();
    cout << endl;
    dwq->action = "梁所长来了!";
    dwq->notify();
    return 0;
}

4.1 示例2 - 代码实现

#include <iostream>
#include <list>
using namespace std;
 
class Observer
{
public:
    virtual void Update(int) = 0;
};
 
class Subject
{
public:
    virtual void Attach(Observer *) = 0;
    virtual void Detach(Observer *) = 0;
    virtual void Notify() = 0;
};
 
class ConcreteObserver : public Observer
{
public:
    ConcreteObserver(Subject *pSubject) : m_pSubject(pSubject){}
 
    void Update(int value)
    {
        cout << "ConcreteObserver get the update. New State:" << value << endl;
    }
 
private:
    Subject *m_pSubject;
};
 
class ConcreteObserver2 : public Observer
{
public:
    ConcreteObserver2(Subject *pSubject) : m_pSubject(pSubject){}
 
    void Update(int value)
    {
        cout << "ConcreteObserver2 get the update. New State:" << value << endl;
    }
 
private:
    Subject *m_pSubject;
};
 
class ConcreteSubject : public Subject
{
public:
    void Attach(Observer *pObserver);
    void Detach(Observer *pObserver);
    void Notify();
 
    void SetState(int state)
    {
        m_iState = state;
    }
 
private:
    std::list<Observer *> m_ObserverList;
    int m_iState;
};
 
void ConcreteSubject::Attach(Observer *pObserver)
{
    m_ObserverList.push_back(pObserver);
}
 
void ConcreteSubject::Detach(Observer *pObserver)
{
    m_ObserverList.remove(pObserver);
}
 
void ConcreteSubject::Notify()
{
    std::list<Observer *>::iterator it = m_ObserverList.begin();
    while (it != m_ObserverList.end())
    {
        (*it)->Update(m_iState);
        ++it;
    }
}
 
int main()
{
    // Create Subject
    ConcreteSubject *pSubject = new ConcreteSubject();
 
    // Create Observer
    Observer *pObserver = new ConcreteObserver(pSubject);
    Observer *pObserver2 = new ConcreteObserver2(pSubject);
 
    // Change the state
    pSubject->SetState(2);
 
    // Register the observer
    pSubject->Attach(pObserver);
    pSubject->Attach(pObserver2);
 
    pSubject->Notify();
 
    // Unregister the observer
    pSubject->Detach(pObserver);
 
    pSubject->SetState(3);
    pSubject->Notify();
 
    delete pObserver;
    delete pObserver2;
    delete pSubject;
}

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

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

相关文章

Alluxio技术分析

Alluxio技术分析 Alluxio: A Virtual Distributed File System Alluxio主要解决的基于磁盘的分布式存储层性能低下的问题&#xff0c;通过alluxio提供的分布式内存来加速数据分析。 Alluxio的这种通过内存加速数据的想法其实是有明确的使用场景的&#xff1a; Immutable da…

【安全】web中的常见编码浅析浏览器解析机制

目录 常见编码 一、ASCII码 二、URL编码 三、Unicode编码 四、HTML实体编码 结合编码理解浏览器解析机制 常见编码 一、ASCII码 ASCII (American Standard Code for Information Interchange&#xff0c;美国信息交换标准代码&#xff09; 计算机内部&#xff0…

QString和QByteArray的区别

QString和QByteArray的区别 本质格式转换QString字符串格式化打印长度 本质 QString是对QByteArray的再次封装 QString可以通过char*来构造&#xff0c;也可以通过QByteArray来构造 QByteArray就是char* QString是编码后的char* QString也是封装了字符串, 但是内部的编码为utf…

Linux笔记——搜索命令find、解压缩命令、vi编辑器、用户权限命令、系统信息相关命令讲解

系列文章目录 Linux笔记——磁盘进行分区与挂载介绍 Linux笔记——管道相关命令以及shell编程 Linux笔记——进程管理与网络监控技术讲解​​​​​​ Linux笔记——rpm与yum下载软件命令介绍 文章目录 系列文章目录 准备工作 一 搜索命令—— find 搜索 1.1 目标 1.…

【UE5 多人联机教程】04-加入游戏

效果 步骤 1. 新建一个控件蓝图&#xff0c;父类为“USC_Button_Standard” 控件蓝图命名为“UMG_Item_Room”&#xff0c;用于表示每一个搜索到的房间的界面 打开“UMG_Item_Room”&#xff0c;在图表中新建一个变量&#xff0c;命名为“Session” 变量类型为“蓝图会话结果…

Matlab 点云曲面特征提取

文章目录 一、简介二、实现代码2.1基于k个邻近点2.2基于邻近半径参考资料一、简介 这里基于每个点的邻域协方差来获取点云中具有的曲面几何特征的点,计算方式如下图所示: 二、实现代码 2.1基于k个邻近点 SurfaceVar.m %% *******</

零信任网络架构与实现技术的研究与思考

目前&#xff0c;国外已有较多有关零信任网络的研究与实践&#xff0c;包括谷歌的 BeyondCorp、BeyondProd&#xff0c;软件定义边界&#xff08;Software Defined Perimeter&#xff0c;SDP&#xff09; 及盖特提出的“持续自适应风险与信任评估”等。国内也有不少安全厂商积极…

Unity 性能优化一:性能标准、常用工具

性能标准 推荐耗时&#xff1a; 性能提现到玩家直观感受&#xff0c;就是帧率&#xff0c;为了达到要求的帧率&#xff0c;就要控制CPU的耗时&#xff0c;不同类型的游戏&#xff0c;对帧率要求不一样。下面是推荐耗时&#xff1a; 推荐内存&#xff1a; 避免游戏闪退的重点…

network failed to load response data: no resource with given ide...

Chrome 开发者工具无法显示服务器正常返回的 HTTP 请求 - Failed to load response data 今天做开发时遇到一个问题&#xff0c;Chrome 开发者工具 network 标签里&#xff0c;虽然一个 HTTP 请求已经成功从服务器端返回&#xff0c;但是 Chrome 开发者工具里&#xff0c;仍然…

Cisco学习笔记(CCNA)——Open Shortest Path First (OSPF)

Open Shortest Path First (OSPF) 动态路由协议介绍 动态路由协议&#xff1a; 向路由表中添加远程网络 探索网络 更新和维护路由表 自主网络探索&#xff1a; 通过共享路由表信息路由器能探索到新的网络 动态路由协议的分类 内部网关协议&#xff08;IGP&#xff09; 适…

华为数通HCIP-ISIS高级

isis区域间的互访 1、L2区域 to L1区域 在L1区域发布的路由会以L1-LSP在L1区域内传递&#xff0c;到达L1-2路由器时&#xff0c;L1-2路由器会将该L1-LSP转换为L2-LSP在L2区域内传递&#xff1b; 因此L2区域的设备可以学习到L1区域的明细路由&#xff0c;进行访问&#xff1b;…

通过 API 远程管理 Jenkins

目录 前言&#xff1a; 背景介绍 Jenkins Remote API 的简介 Jenkins Remote API 的调用 Read More ... 前言&#xff1a; Jenkins 是一种开源的持续集成工具&#xff0c;可以帮助我们更加方便地进行软件开发和测试工作。通过 API 远程管理 Jenkins 可以帮助我们更加方便…

Windows 11 22H2 中文版、英文版 (x64、ARM64) 下载 (updated Jul 2023)

Windows 11 22H2 中文版、英文版 (x64、ARM64) 下载 (updated Jul 2023) Windows 11, version 22H2 官方原版&#xff0c;2023 年 7 月 更新 请访问原文链接&#xff1a;https://sysin.org/blog/windows-11/&#xff0c;查看最新版。原创作品&#xff0c;转载请保留出处。 作…

(三)RabbitMQ七种模式介绍与代码演示

Lison <dreamlison163.com>, v1.0.0, 2023.06.22 七种模式介绍与代码演示 文章目录 七种模式介绍与代码演示四大交换机四种交换机介绍 工作模式简单模式&#xff08;Hello World&#xff09;工作队列模式&#xff08;Work queues&#xff09;订阅模式&#xff08;Publis…

Qt 类似vscode和matlab的分屏显示效果

运行截图 向右分屏 多分屏 全屏显示 介绍 实现了一个类似vscode和matlab的标签页显示分屏效果&#xff0c;支持鼠标拖拽分屏、全屏显示&#xff0c;可自适应调整大小&#xff0c;程序把要显示的Widget独立出来&#xff0c;可随时替换为其他的用户自定义Widget&#xff0c…

挂载文件系统

文章目录 注册文件系统类型挂载文件系统系统调用mount绑定挂载挂载命名空间1.标准的挂载命名空间2.共享子树&#xff08;1&#xff09;共享挂载&#xff08;2&#xff09;从属挂载&#xff08;3&#xff09;私有挂载&#xff08;4&#xff09;不可绑定挂载 挂载跟文件系统1.根文…

YOLOv5改进RepViT结构:清华 ICCV 2023,原创Bottleneck设计

RepViT: Revisiting Mobile CNN From ViT Perspective 论文方法从块设计改进YOLOv5结构核心代码1核心代码2核心代码3yaml1yaml2yaml3论文:https://arxiv.org/pdf/2307.09283.pdf   代码:https://github.com/THU-MIG/RepViT 最近,轻量级视觉 Trans

Android App 持续集成性能测试:启动流量

目录 前言&#xff1a; get app UID 获取流量数据 获得启动流量数据 总结 前言&#xff1a; Jenkins 是一种开源的持续集成工具&#xff0c;可以帮助我们更加方便地进行软件开发和测试工作。通过 API 远程管理 Jenkins 可以帮助我们更加方便地进行 Jenkins 的配置和管理工…

临时文档3

值传递 当一个对象被当作参数传递到一个方法后&#xff0c;此方法可改变这个对象的属性&#xff0c;并可返回变化后的结果&#xff0c;那么这里到底是值传递还是引用传递 是值传递。Java 语言的方法调用只支持参数的值传递。当一个对象实例作为一个参数被传递到方法中时&…

什么是Java中的JVM(Java虚拟机)?

JVM&#xff08;Java虚拟机&#xff09;是Java平台的核心组件之一&#xff0c;是一个用于执行Java字节码的虚拟计算机。Java源代码经过编译器编译&#xff0c;生成字节码文件&#xff08;.class文件&#xff09;&#xff0c;然后由JVM来解释和执行这些字节码。JVM负责将字节码翻…