【设计模式】观察者模式及函数式编程的替代C++

news2024/11/16 12:49:10

本文介绍观察者模式以及使用函数式编程替代简单的策略模式。

观察者模式

观察者模式是一种行为型设计模式,它定义了一种一对多的依赖关系,当一个对象的状态发生改变时,其所有依赖者都会收到通知并自动更新。

当对象间存在一对多关系时,则使用观察者模式(Observer
Pattern)。比如,当一个对象被修改时,则会自动通知依赖它的对象。观察者模式属于行为型模式。

简单来说,观察者模式需要多个对象观察同一个对象,被观察的对象称为Subject(主题),Subject需要完成观察者的注册(attach),注销(detach)和通知(notify)三个操作。
观察者模式,图片来自菜鸟教程
首先实现一个公共的Observer父类,这个父类只有一个纯虚函数,用来更新自身状态:

struct Observer
{
public:
    virtual void update() = 0;
};

两个具体的类,实现 update 函数:

struct ConcreteObserver : Observer
{
public:
    void update() override
    {
        std::cout << "State updated!" << std::endl;
    }
};

struct ConcreteObserver2 : Observer
{
public:
    void update() override
    {
        std::cout << "State updated! 2" << std::endl;
    }
};

接下来实现被观察者公共类,包含添加、删除、通知所有观察者三个接口:

struct Subject
{
public:
    virtual void attach(Observer *observer) = 0;
    virtual void detach(Observer *observer) = 0;
    virtual void notify() = 0;
};

具体的被观察者类,实现这三个接口:

struct ConcreteSubject : Subject
{
public:
    void attach(Observer *observer) override
    {
        observers.push_back(observer);
    }

    void detach(Observer *observer) override
    {
        for (auto it = observers.begin(); it != observers.end(); it++)
        {
            if (*it == observer)
            {
                observers.erase(it);
                break;
            }
        }
    }

    void notify() override
    {
        for (auto &observer : observers)
        {
            observer->update();
        }
    }

private:
    std::vector<Observer *> observers;
};

测试代码如下:

int main()
{
    ConcreteSubject subject;
    ConcreteObserver observer1;
    ConcreteObserver2 observer2;

    subject.attach(&observer1);
    subject.attach(&observer2);

    subject.notify();

    subject.detach(&observer1);

    subject.notify();
}

结果

函数式编程下的观察者模式

首先需要介绍下C语言的函数指针。所谓函数指针即定义一个指向函数的指针变量,格式如下:

typedef void (*Callback)();

这样就定义了一个变量名为Callback的指针变量,指向一个参数为void,返回值也为void的函数。我们用这种指针变量,就能将整个观察者类改成函数。

两个观察者函数:

void callback1()
{
    std::cout << "State updated!" << std::endl;
}

void callback2()
{
    std::cout << "State updated! 2" << std::endl;
}

被观察的类。原先调用观察者类的地方全部改为函数调用:

struct ConcreteSubject
{
public:
    void attach(Callback callback)
    {
        observers.push_back(callback);
    }

    void detach(Callback callback)
    {
        for (auto it = observers.begin(); it != observers.end(); it++)
        {
            if (*it == callback)
            {
                observers.erase(it);
                break;
            }
        }
    }

    void notify()
    {
        for (auto &observer : observers)
        {
            observer();
        }
    }

private:
    std::vector<Callback> observers;
};

观察者模式与回调

我给函数指针起名为Callback。事实上,当只有一个观察者的时候,观察者模式的机制就等同于回调模式。因此可以认为,回调模式是一种特殊的观察者模式。

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

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

相关文章

flutter 文字一行显示,超出换行

因为app有多语言&#xff0c;中文和其他语言长度不一致&#xff0c;可能导致英文会很长。 中文样式 英文样式 代码 Row(mainAxisAlignment: MainAxisAlignment.end,crossAxisAlignment: CrossAxisAlignment.end,children: [Visibility(visible: controller.info.fee ! null,ch…

更详细的软件测试理论基础:流程,开发、测试模型,测试分类,测试用例及其设计方法,缺陷

文章目录 一、测试流程二、开发模型1、 瀑布模型2、增量模型3、快速模型4、其他 三、测试模型1、V模型2、W模型 四、测试分类五、测试用例 test case六、测试用例设计方法1、等价类划分法2、边界值分析法3、因果图法4、判定表法5、正交法6、场景法7、流程分析法8、错误推测法方…

Apipost自动化测试持续集成配置方法

安装 Apipost-cli npm install -g apipost-cli 运行脚本 安装好Apipost-cli后&#xff0c;在命令行输入生成的命令&#xff0c;即可执行测试用例&#xff0c;运行完成后会展示测试进度并生成测试报告。 Jenkins配置 Apipost cli基于Node js运行 需要在jenkins上配置NodeJs依…

基于springboot+vue的流浪动物救助网站(源码+论文)

目录 前言 一、功能实现 1 普通员工 1.1普通员工登录 1.2圈子信息 1.3志愿者 1.4求助 1.5资源 1.6寄养 2 系统管理员 2.1管理员登录 2.2圈子信息 2.3志愿者 2.4 求助 2.5 资源 2.6 领养 2.7个人信息 二、库表设计 三、论文 前言 随着生活的加快以及互联网时…

Mybatis_plus-逻辑删除、通用枚举、自动填充、插件等

一、逻辑删除 曾经我们写的删除代码都是物理删除。 逻辑删除&#xff1a;删除转变为更新 ​ update user set deleted1 where id 1 and deleted0 查找: 追加 where 条件过滤掉已删除数据,如果使用 wrapper.entity 生成的 where 条件也会自动追加该字段 ​ 查找: select id,nam…

数据审计 -本福德定律 Benford‘s law (sample database classicmodels _No.6)

数据审计 -本福德定律 Benford’s law 准备工作&#xff0c;可以去下载 classicmodels 数据库资源如下 [ 点击&#xff1a;classicmodels] 也可以去我的博客资源下载 文章目录 数据审计 -本福德定律 Benfords law 前言一、什么是 本福德定律&#xff1f;二、数学公式三、应用…

jetson nano——编译安装opencv==4.4

目录 1.下载源码&#xff0c;我提供的链接如下&#xff1a;1.1文件上传的路径位置&#xff0c;注意ymck是我自己的用户名&#xff08;你们自己换成你们自己相对应的就行&#xff09; 2.解压文件3.安装依赖4.增加swap交换内存4.1临时增加交换内存swap4.2永久增加swap 5.安装open…

MySQL进阶:MySQL事务、并发事务问题及隔离级别

&#x1f468;‍&#x1f393;作者简介&#xff1a;一位大四、研0学生&#xff0c;正在努力准备大四暑假的实习、 &#x1f30c;上期文章&#xff1a;MySQL进阶&#xff1a;视图&&存储过程&&存储函数&&触发器 &#x1f4da;订阅专栏&#xff1a;MySQL进…

今日学习总结2024.3.2

最近的学习状态比较好&#xff0c;感觉非常享受知识进入脑子的过程&#xff0c;有点上头。 实验室一个星期唯一一天的假期周六&#xff0c;也就是今天&#xff0c;也完全不想放假出去玩啊&#xff0c;在实验室泡了一天。 很后悔之前胆小&#xff0c;没有提前投简历找实习&…

实现数组方法 forEach map filter every

手写forEach Array.prototype.myforEach function (fn, thisValue) {let index 0;let arr thisValue || this;if (typeof fn ! function) {throw new TypeError(fn is not a function)}while (index < arr.length) {if (index in arr) {fn.call (thisValue, arr[index],…

VUE3中的组件传值

一、父传子(props) 在子组件中可以使用defineProps接收父组件向子组件的传值 父组件fatherPage.vue&#xff1a; <template><div class"father"><button click"a a 1">按钮</button><childPage :a"a" /><…

【Python】进阶学习:pandas--groupby()用法详解

&#x1f4ca;【Python】进阶学习&#xff1a;pandas–groupby()用法详解 &#x1f308; 个人主页&#xff1a;高斯小哥 &#x1f525; 高质量专栏&#xff1a;Matplotlib之旅&#xff1a;零基础精通数据可视化、Python基础【高质量合集】、PyTorch零基础入门教程&#x1f448;…

全面整理!机器学习常用的回归预测模型

Datawhale干货 作者&#xff1a;曾浩龙&#xff0c;Datawhale意向成员 前言 回归预测建模的核心是学习输入 到输出 &#xff08;其中 是连续值向量&#xff09;的映射关系。条件期望 是 到 的回归函数。简单来说&#xff0c;就是将样本的特征矩阵映射到样本标签空间。 图…

spring boot 整合 minio存储 【安装篇】

一、minio是什么&#xff1f; MinIO 是一个基于Apache License v2.0开源协议的对象存储服务。它兼容亚马逊S3云存储服务接口&#xff0c;非常适合于存储大容量非结构化的数据&#xff0c;例如图片、视频、日志文件、备份数据和容器/虚拟机镜像等&#xff0c;而一个对象文件可以…

每日OJ题_牛客_合法括号序列判断

目录 合法括号序列判断 解析代码 合法括号序列判断 合法括号序列判断__牛客网 解析代码 class Parenthesis {public:bool chkParenthesis(string A, int n){if (n & 1) // 如果n是奇数return false;stack<char> st;for (int i 0; i < n; i) {if (A[i] () {s…

【Godot4.2】控件节点生成与布局函数库Ctl

前言 本文依旧来自笔者的语雀知识库。基础内容写于2023年8月份。当时写的比较随意&#xff0c;本篇将在其基础上扩充和修改。 概述 Godot本身提供了丰富的控件和容器来实现UI布局&#xff0c;但是这个过程往往需要复杂的手动操作和配置&#xff0c;使用代码生成方式时也会需…

java-ssm-jsp-宠物常规护理知识管理系统设计与实现

java-ssm-jsp-宠物常规护理知识管理系统设计与实现 获取源码——》公主号&#xff1a;计算机专业毕设大全

Ubuntu20.04: UE4.27 中 Source Code 的编辑器下拉框没有 Rider选项

问题描述 最近想用 Rider 作为 UE4 开发的 IDE&#xff0c;但安装好 Rider 后&#xff0c;发现编辑器下拉框中没有 Rider 的选项&#xff0c;我检查了 UE4 的插件&#xff0c;发现 Rider Integration 插件已经安装且启用的。 环境&#xff1a;Ubuntu 20.04 UE4.27 Rider2023…

设计模式(十四)中介者模式

请直接看原文: 原文链接:设计模式&#xff08;十四&#xff09;中介者模式_设计模式之中介模式-CSDN博客 -------------------------------------------------------------------------------------------------------------------------------- 前言 写了很多篇设计模式的…

洛谷 B3620 x 进制转 10 进制

题目描述 给一个小整数 x 和一个 x 进制的数 S。将 S 转为 10 进制数。对于超过十进制的数码&#xff0c;用 A&#xff0c;B&#xff0c;…… 表示。 输入格式 第一行一个整数 x; 第二行一个字符串 S。 输出格式 输出仅包含一个整数&#xff0c;表示答案。 输入输出样例…