观察者模式说明(C语言版本)

news2025/2/21 21:04:02

观察者模式主要是为了实现一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。下面使用C语言实现了一个具体的应用示例,有需要的可以参考下

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>

// 观察者的结构定义
typedef struct {
    void (*add)(void *data);
    void (*update)(void *data);
    void (*delete)(void *data);
} observer_t;

// 观察者链表节点定义
typedef struct _observer_list_t {
    observer_t *observer;
    struct _observer_list_t *next;
} observer_list_t;

// 被观察者定义
typedef struct _subject_t {
    void *data;
    observer_list_t *observer; // 观察者链表
} subject_t;

// 初始化观察者的更新函数
void init_observer_update(observer_t *observer, void (*update)(void *data)) {
    observer->update = update;
}

// 初始化观察者的添加函数
void init_observer_add(observer_t *observer, void (*add)(void *data)) {
    observer->add = add;
}

// 初始化观察者的删除函数
void init_observer_delete(observer_t *observer, void (*delete)(void *data)) {
    observer->delete = delete;
}

// 加入观察者队列
bool attach_observer(subject_t *subject, observer_t *observer) {
    observer_list_t *node = (observer_list_t *)malloc(sizeof(observer_list_t));
    if (!node) return false; // 内存分配失败

    node->observer = observer;
    node->next = subject->observer;
    subject->observer = node;
    return true;
}

// 从观察者队列删除
bool detach_observer(subject_t *subject, observer_t *observer) {
    observer_list_t *node = subject->observer;
    observer_list_t *prev = NULL;

    while (node) {
        if (node->observer == observer) {
            if (prev) {
                prev->next = node->next;
            } else {
                subject->observer = node->next;
            }
            free(node);
            return true;
        }
        prev = node;
        node = node->next;
    }
    return false; // 未找到观察者
}

// 修改被观察数据
void set_observer_data(subject_t *subject, void *value) {
    subject->data = value;
}

// 通知观察者更新
void notify_observer_update(subject_t *subject) {
    observer_list_t *node = subject->observer;
    int count = 0;
    for (; node; node = node->next) {
        printf("Notify observer update %d. Data: %s\n", count, (char *)subject->data);
        count++;
        if (node->observer->update) {
            node->observer->update(subject->data);
        }
    }
}

// 通知观察者添加(这个在实际应用中可能不常见,通常只通知更新或删除)
void notify_observer_add(subject_t *subject) {
    // ...(类似notify_observer_update,但调用add函数)
    // 这里为了简洁省略,实际应用中根据需要实现
}

// 通知观察者删除(同样,这个在标准观察者模式中不常见)
void notify_observer_delete(subject_t *subject) {
    // ...(类似notify_observer_update,但调用delete函数)
    // 这里为了简洁省略,实际应用中根据需要实现
}

// 初始化主题对象
void init_subject(subject_t *subject) {
    memset(subject, 0, sizeof(subject_t));
}

// 释放主题对象及其所有观察者
void free_subject(subject_t *subject) {
    observer_list_t *node = subject->observer;
    while (node) {
        observer_list_t *temp = node;
        node = node->next;
        free(temp);
    }
    // 注意:这里没有释放subject->data,因为不清楚其分配方式。在实际应用中需要适当处理。
}

使用示例

// 假设我们有一个简单的字符串观察者,它会打印接收到的字符串
void observer_update(void *data) {
    printf("Observer received update: %s\n", (char *)data);
}

int main() {
    // 创建一个主题对象
    subject_t subject;
    init_subject(&subject);

    // 创建一个观察者并初始化其更新函数
    observer_t observer;
    init_observer_update(&observer, observer_update);

    // 将观察者附加到主题对象
    attach_observer(&subject, &observer);

    // 设置被观察数据并通知观察者
    set_observer_data(&subject, "Hello, Observer!");
    notify_observer_update(&subject);

    // 从主题对象中删除观察者
    detach_observer(&subject, &observer);

    // 释放主题对象(在实际应用中,通常在程序结束时进行)
    free_subject(&subject);

    return 0;
}

执行结果

在这里插入图片描述

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

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

相关文章

【从0做项目】Java搜索引擎(6) 正则表达式鲨疯了优化正文解析

阿华代码&#xff0c;不是逆风&#xff0c;就是我疯 你们的点赞收藏是我前进最大的动力&#xff01;&#xff01; 希望本文内容能够帮助到你&#xff01;&#xff01; 目录 文章导读 零&#xff1a;项目结果展示 一&#xff1a;导读&知识点回顾 二&#xff1a;遗留问题 …

【论文技巧】Mermaid VSCode插件制作流程图保存方法

插流程图快点 利用Mermaid Preview插件自带功能 如果你的VSCode安装了支持导出图片的Mermaid预览插件&#xff08;如 Mermaid Markdown Syntax Highlighting 等&#xff09;&#xff0c;可以按以下步骤进行&#xff1a; 打开Mermaid代码文件&#xff1a;在VSCode中打开包含M…

【DeepSeek】如何将DeepSeek部署到本地?如何给本地 LLM 提供UI界面?CherryStudio 的使用

注&#xff1a;如果下面的所有操作&#xff0c;需要访问到 Github&#xff0c;可以先看这篇文章&#xff0c;了解如何流畅连接 Github 【Github】如何流畅链接Github.com-CSDN博客 一、下载 Ollama 1、访问网址 Ollama&#xff0c;点击下载 Ollama 到本地 选择自己计算机的系统…

mac开发环境配置笔记

1. 终端配置 参考&#xff1a; Mac终端配置笔记-CSDN博客 2. 下载JDK 到 oracle官网 下载jdk: oracle官网 :Java Downloads | Oraclemac的芯片为Intel系列下载 x64版本的jdk&#xff1b;为Apple Mx系列使用 Arm64版本&#xff1b;oracle官网下载时报错&#xff1a;400 Bad R…

交换机基本命令

目录 一、华为交换机基本命令 1、VRP视图层 2、命令帮助 3、配置设备名称 4、命令等级&#xff08;一般生产过程没有下面的详细&#xff09; 5、用户界面 6、配置Console认证 控制台接口&#xff08;Console&#xff09; 配置步骤示例 7、配置VTY登录&#xff08;本文…

PHP图书借阅小程序源码

&#x1f4da; 图书借阅小程序&#xff1a;一键开启智慧阅读新篇章 &#x1f31f; 这是一款由ThinkPHP与UniApp两大技术巨擘强强联手精心打造的图书借阅微信小程序&#xff0c;它犹如一座随身携带的移动图书馆&#xff0c;让您无论身处何地都能轻松畅游知识的海洋。创新的多书…

UE 播放视频

一.UI播放视频 1.导入视频文件至工程文件夹 2.文件夹内右健选择Media -> File Meida Source创建testFileMeidaSource文件。 编辑FilePath为当前视频 3.右键->Media->Media Player 创建testMediaPlayer文件 4.右键创建testMediaTexture。编辑MediaPlayer设置testMedia…

拦截器VS过滤器:Spring Boot中请求处理的艺术!

目录 一、拦截器&#xff08;Interceptor&#xff09;和过滤器&#xff08;Filter&#xff09;&#xff1a;都是“守门员”&#xff01;二、如何实现拦截器和过滤器&#xff1f;三、拦截器和过滤器的区别四、执行顺序五、真实的应用场景六、总结 &#x1f31f;如果喜欢作者的讲…

react实例与总结(二)

目录 一、脚手架基础语法(16~17) 1.1、hello react 1.2、组件样式隔离(样式模块化) 1.3、react插件 二、React Router v5 2.1、react-router-dom相关API 2.1.1、内置组件 2.1.1.1、BrowserRouter 2.1.1.2、HashRouter 2.1.1.3、Route 2.1.1.4、Redirect 2.1.1.5、L…

巧用GitHub的CICD功能免费打包部署前端项目

近年来&#xff0c;随着前端技术的发展&#xff0c;前端项目的构建和打包过程变得越来越复杂&#xff0c;占用的资源也越来越多。我有一台云服务器&#xff0c;原本打算使用Docker进行部署&#xff0c;以简化操作流程。然而&#xff0c;只要执行sudo docker-compose -f deploy/…

使用 DeepSeek 生成商城流程图

步骤 1.下载 mermaid 2.使用 DeepSeek 生成 mermaid 格式 3.复制内容到 4.保存备用。 结束。

VSCode自定义快捷键和添加自定义快捷键按键到状态栏

VSCode自定义快捷键和添加自定义快捷键按键到状态栏 &#x1f4c4;在VSCode中想实现快捷键方式执行某些指令操作&#xff0c;可以通过配置组合式的键盘按键映射来实现&#xff0c;另外一种方式就是将执行某些特定的指令嵌入在面板菜单上&#xff0c;在想要执行的时候&#xff0…

Ubuntu22.04 - gflags的安装和使用

目录 gflags 介绍gflags 安装gflags 使用 gflags 介绍 gflags 是Google 开发的一个开源库&#xff0c;用于 C应用程序中命令行参数的声明、定义和解析。gflags 库提供了一种简单的方式来添加、解析和文档化命令行标志(flags),使得程序可以根据不同的运行时配置进行调整。 它具…

java | MyBatis-plus映射和golang映射对比

文章目录 Java实体类和数据库的映射1.默认驼峰命名规则2.自定义字段映射3.关闭驼峰命名规则4.JSON序列化映射 Golang1. 结构体与表的映射2. 字段与列的映射3. 关联关系映射4. 其他映射相关标签 这篇也是做数据库映射方面的对比&#xff1a; Java 实体类和数据库的映射 1.默认…

正则表达式–断言

原文地址&#xff1a;正则表达式–断言 – 无敌牛 欢迎参观我的个人博客&#xff1a;正则表达式特殊字符 – 无敌牛 断言assertions 1、(?...)&#xff1a;正向预查&#xff08;positive lookahead&#xff09;&#xff0c;表示某个字符串后面应该跟着什么。但这个字符串本身…

电脑想安装 Windows 11 需要开启 TPM 2.0 怎么办?

尽管 TPM 2.0 已经内置在许多新电脑中&#xff0c;但很多人并不知道如何激活这一功能&#xff0c;甚至完全忽略了它的存在。其实&#xff0c;只需简单的几步操作&#xff0c;你就能开启这项强大的安全特性&#xff0c;为你的数字生活增添一层坚固的防护屏障。无论你是普通用户还…

QT之改变鼠标样式

QT改变鼠标图片 资源路径如下 代码实现 QPixmap customCursorPixmap(":/images/mouse.png");QCursor customCursor(customCursorPixmap);QWidget::setCursor(customCursor); // 可以设置为整个窗口或特定控件QWidget::setCursor(); // 设置为透明光标&#xff0c…

ue----git局域网内部署裸仓库,别的机器进行访问

最近由于经常迁移项目到另一台机器上进行部署更新一点就要整个迁移 弄得麻烦了 就在网上学了一下这个方式 首先我们在想要建立裸仓库的电脑上找到一个文件夹放置我们的裸仓库 在此点击鼠标右键选择 open git bash here 输入命令 创裸仓库 git init --bare gitTestName.git…

PaddlePaddle的OCR模型转onnx-转rknn模型_笔记4

一、PaddlePaddle的OCR模型转onnx 1、首先建立一个新的虚拟环境 conda create -n ppocr python3.10 -y conda activate ppocr 2、进入paddlepaddle官网输入以下指令安装paddlepaddle GPU版本 &#xff08;我的cuda版本是11.8,根据你电脑装合适版本&#xff09; pip instal…

【大模型系列篇】DeepSeek-R1如何通过强化学习有效提升大型语言模型的推理能力?

如何通过强化学习&#xff08;RL&#xff09;有效提升大型语言模型&#xff08;LLM&#xff09;的推理能力&#xff1f; 《DeepSeek-R1: Incentivizing Reasoning Capability in LLMs via Reinforcement Learning》由DeepSeek-AI团队撰写&#xff0c;主要介绍了他们开发的第一代…