我用C语言玩对象,观察者模式应用1-订报

2023-05-16

概述

观察者模式让多个观察者对象同时监听某一个主题对象。这个主题对象在状态变化时,会通知所有的观察者对象,使他们能够自动更新自己。

之前的文章已经详细阐述了这种设计模式的核心和注意事项,并完成了基类设计,请参见《我用C语言玩对象,偷偷关注着你的观察者模式(基类设计)》,本文将结合实际案例论证这种设计模式,加深读者对观察者模式的理解和应用。

示例

★背景说明:人民日报+订阅者=观察者模式。只要是订阅了人民日报的人,有了新报纸就会送到订阅者那里去,当你不想订的时候取消就不订阅就不会再收到报纸了。

★被观察者对象(人民日报):

属性:无

行为:获取报纸。

继承:继承被观察者基类

★观察者对象(订阅者):

属性:名字

行为:对应行为。

★包含头文件newspaper.h和源文件newspaper.c(均已验证通过)。

 newspaper.h

/**
 * @Filename : newspaper.h
 * @Revision : $Revision: 1.0 $
 * @Author : Feng(更多编程相关的知识和源码见微信公众号:不只会拍照的程序猿,欢迎订阅)
 * @Description : 观察者模式应用(C语言模拟C++)
 * @Explain : 报纸(被观察者)  newspaper    
              seven(观察者)  subscribe   订阅者 有报纸即通知
              feng(观察者)   subscribe   订阅者 有报纸即通知
**/

#ifndef __NEWSPAPER_H__
#define __NEWSPAPER_H__

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "observer.h"

/* 被观察者(报纸)类定义 */
struct newspaper {
    struct oble oble;   /* 继承被观察者基类 */
    void (*get)(struct newspaper *p_news);    /* 获取报纸 */
};

/**
 * @创建人民日报对象
 * @成功返回类对象,失败返回NULL
**/
struct newspaper *new_newspaper(void);

/* 观察者(订阅者)类定义 */
struct subscribe {
    struct ober ober;
    char name[16];
};

/**
 * @创建订阅者对象
 * @name:订阅者名字
 * @成功返回类对象,失败返回NULL
**/
struct subscribe *new_subscribe(char *name);

#endif

 newspaper.c

/**
 * @Filename : newspaper.c
 * @Revision : $Revision: 1.0 $
 * @Author : Feng(更多编程相关的知识和源码见微信公众号:不只会拍照的程序猿,欢迎订阅)
 * @Description : 观察者模式应用(C语言模拟C++)
 * @Explain : 报纸(被观察者)  newspaper    
              seven(观察者)  subscribe   订阅者 有报纸即通知
              feng(观察者)   subscribe   订阅者 有报纸即通知
**/

#include "newspaper.h"

/**
 * @获取报纸
 * @p_news:报纸类
**/
static void _get_paper(struct newspaper *p_news)
{
    p_news->oble.notify((struct oble *)p_news);
} 

/**
 * @创建报纸对象
 * @成功返回类对象,失败返回NULL
**/
struct newspaper *new_newspaper(void)
{
    struct oble *p_oble;
    struct newspaper *p_news;

    p_news = (struct newspaper *)malloc(sizeof(struct newspaper));

    if (p_news == NULL)
        return NULL;

    memset((char *)p_news, 0, sizeof(struct newspaper));

    if ((p_oble = new_oble()) == NULL) {
        free(p_news);
        return NULL;
    }
    memcpy(&(p_news->oble), p_oble, sizeof(struct oble));
    free(p_oble);

    p_news->get = _get_paper;

    return p_news;
}

/**
 * @通知订阅者
 * @ p_oble:被观察者类       p_ober:观察者类
**/
static void _update(struct ober *p_ober, struct oble *p_oble)
{
    struct subscribe *p_sub = (struct subscribe *)p_ober;
    printf("%s : have newspaper...\n", p_sub->name);
}

/**
 * @创建订阅者对象
 * @name:订阅者名字
 * @成功返回类对象,失败返回NULL
**/
struct subscribe *new_subscribe(char *name)
{
    struct ober *p_ober;
    struct subscribe *p_sub;

    p_sub = (struct subscribe *)malloc(sizeof(struct subscribe));

    if (p_sub == NULL)
        return NULL;

    memset((char *)p_sub, 0, sizeof(struct subscribe));

    if ((p_ober = (struct ober *)malloc(sizeof(struct ober))) == NULL) {
        free(p_sub);
        return NULL;
    }

    p_ober->update = _update;
    memcpy(&(p_sub->ober), p_ober, sizeof(struct ober));
    free(p_ober);

    strcpy(p_sub->name, name);

    return p_sub;
}

/**
 * @主函数,演示代码
**/
int main(void)
{   
    struct subscribe *p_seven = new_subscribe("seven");
    struct subscribe *p_feng = new_subscribe("feng");

    struct newspaper *p_news = new_newspaper();

    if ((p_news == NULL) || (p_seven == NULL) || (p_feng == NULL)) {
        printf("create observable class failed...\n");
        return -1;
    }

    /* seven 和 feng 同时订阅了人民日报 */
    p_news->oble.add(&(p_news->oble), &(p_seven->ober));
    p_news->oble.add(&(p_news->oble), &(p_feng->ober));

    p_news->get(p_news);    /* 报纸来了,seven 和 feng应同时被通知 */

    printf("------------------------------\n");

    /* feng 取消订阅人民日报 */
    p_news->oble.rm(&(p_news->oble), &(p_feng->ober));
    p_news->get(p_news);    /* 报纸来了,只有seven被通知 */

    return 0;
}

结论

输入示例代码运行,结果如下:

feng:observer$ gcc -o newspaper newspaper.c observer.c class_dll.c dll.c
feng:observer$ ./newspaper
seven : have newspaper...
feng : have newspaper...
------------------------------
seven : have newspaper...
feng:observer$ 

分析:示例定义了人民日报对象作为被观察者,同时定义了seven和feng对象作为观察者,开始的时候,seven和feng均订阅了人民日报,所以当发报纸的时候,seven和feng均能收到通知,后来,feng取消订阅,所以发报纸的时候只有seven能收到通知。

往期 · 推荐

也没想象中那么神秘的数据结构-先来后到的“队列”(链式队列)

也没想象中那么神秘的数据结构-先来后到的“队列”(循环队列)

也没想象中那么神秘的数据结构-后来居上的“栈”

我用C语言玩对象,观察者模式应用2-热水的用途

我用C语言玩对象,状态模式应用1-水的三态

关注

更多精彩内容,请关注微信公众号:不只会拍照的程序猿,本人致力分享linux、设计模式、C语言、嵌入式、编程相关知识,也会抽空分享些摄影相关内容,同样也分享大量摄影、编程相关视频和源码,另外你若想要本文章源码请关注公众号:不只会拍照的程序猿,后台回复:设计模式源码,也可点击此处下载

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

我用C语言玩对象,观察者模式应用1-订报 的相关文章

  • git reset 的灵活应用

    git reset 常用有三种方式 xff1a 方式影响说明git reset soft只回退 commit 操作影响最小 xff0c 重新 commit 即可git reset mixed回退 commit 和 add 操作默认方式 xf
  • Mac 连接显示器,外接显示器不出影像

    1 现象 转换头 xff0c 连接线已正确连接 xff1b 显示器电源等也亮 xff0c 且是已有视频信号的状态 xff1b 查看设置 显示器 xff0c 里面也显示识别出已连接外接显示器 2 解决办法 显示器支持的 最高刷新率 与 系统设
  • idea多模块打包

    多模块打包的办法有两个 1 在parent的pom下执行deploy 这样就会自动将父 pom以及子 module都发布到仓库 在模块中添加如下选项 lt distributionManagement gt lt repository gt
  • Xcode 模拟器如何录屏

    1 touch bar 录制图标 有touch bar的MacBook xff0c 模拟器为当前最前窗口事 xff0c touch bar 上点击录制图标即可 xff1b 2 快捷键 选中模拟器界面 xff0c command 43 R 3
  • iOS 组件中设置文件支持MRC

    1 设置该文件的Compiler Flags 为 fno objc arc 使用cocopods 加载此组件时 xff0c 在 Pods 下的 Build Phases 中的 Compile Sources目录中 找到想要设置的文件 xff
  • Null passed to a callee that requires a non-null argument 【iOS常见报错收集】

    1 问题描述 xff1a xcode提示如下 xff1a 2 问题原因 此处某参数未设置 Nullable xff0c 但是赋值了nil xff0c xcode自动提示防止nil导致异常 xff1b 3 解决办法 将此处有可能传入nil的参
  • win10扩展EFI分区

    Win10扩展EFI分区 由于需要在Win10上安装Ubuntu18 04双系统 xff0c 硬盘格式为GPT xff0c 安装过程中需要将Ubuntu的引导分区设置Win10的EFI分区 xff0c 但是win10的EFI分区装系统时默认
  • 桌面图标美化,图包分享

    图标修改教程 先放效果图 xff1a 直接进入正题 xff1a 此电脑 网络 回收站等 xff1a 桌面右键 gt 个性化 gt 主题 gt 相关的设置 gt 桌面图标设置 应用等 xff1a 右键应用 gt 属性 系统图标 xff0c 以
  • Spring注解原理的详细剖析与实现

    一 注解的基本概念和原理及其简单实用 注解 xff08 Annotation xff09 提供了一种安全的类似注释的机制 xff0c 为我们在代码中添加信息提供了一种形式化得方法 xff0c 使我们可以在稍后某个时刻方便的使用这些数据 xf
  • Java实现集合的组合(从组合中取出K个元素进行组合的所有情况)

    1 利用递归进行取出数据 span class hljs keyword public span static span class hljs subst lt span T span class hljs subst gt span sp
  • 浅谈Dockerfile文件

    DockerFile dockerfile是用来构建Docker镜像的构建文件 xff0c 是由一系列命令和参数构成的脚本 DockerFile构建过程解析 Dockerfile内容基础知识 每条保留字指令都必须为大写字母且后面要跟随至少一
  • Java基础学习 100 问

    Java基础学习 100 问 来源 xff1a 赢在面试 xff08 Java知音 javascript void 0 x1f609 xff09 一 Java基础篇 1 一个 34 java 34 源文件中是否可以包括多个类 xff08 不
  • Windows下误删EFI分区重建引导简单教程

    环境 xff1a windows10 xff0c 其余环境未经测试 EFI百度词条解释如下 xff1a EFI system partition ESP xff0c EFI 系统分区通常指数据存储介质中的一个分区 xff0c 通常用于硬盘或
  • maven导入本地jar包

    最近看 https github com junicorn kira 实现的java的代码 有个库发现没法使用maven安装 https mvnrepository com artifact com bladejava blade kit
  • TensorFlow入门教程(23)将图像超分辨率模型SRGAN移植到安卓APP(下)

    作者 xff1a 韦访 博客 xff1a https blog csdn net rookie wei 微信 xff1a 1007895847 添加微信的备注一下是CSDN的 欢迎大家一起学习 1 概述 上一讲我们将SRGAN模型由HDF5
  • (四)生产者消费者模式

    xff08 一 生产者消费者模式原理 xff1a 在一个系统中 xff0c 存在生产者和消费者两种角色 xff0c 他们通过内存缓冲区进行通信 xff0c 生产者生产消费者需要的资料 xff0c 消费者把资料做成产品 生产消费者模式如下图
  • Ubuntu 18.04串口终端开机免密自动登录

    Ubuntu 18 04串口终端开机免密自动登录 serial getty开机设置选项 ubuntu18 04已经不再使用initd管理系统 改用systemd serial getty span class token comment v
  • NRF52840 用RTT打印log配置方法

    1 在sdk config h中配置两个宏 xff1a NRF LOG ENABLED 1 NRF LOG BACKEND RTT ENABLED 1 2 需要初始化NRF LOG static void log init void ret

随机推荐