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

2023-10-13 03:10

本文主要是介绍我用C语言玩对象,观察者模式应用2-热水的用途,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

概述

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

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

示例

★背景说明:水温在50℃~ 70℃时, 会发出警告:可以用来洗澡了!水温在100℃时也会发出警告:可以用来饮用了!在这里洗澡模式和饮用模式扮演了监听的角色, 而热水器则是被监听的对象。一旦热水器中的水温度发生变化, 监听者就能及时知道并做出相应的判断和动作。这就是程序设计中监听模式的生动展现。

★被观察者对象(热水器):

属性:温度(当前热水器水温)

行为:获取水温、设置水温。

继承:继承被观察者基类

★观察者对象(洗澡模式、喝水模式):

属性:无

行为:对应行为。

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

 water_heater.h

/*** @Filename : water_heater.h* @Revision : $Revision: 1.0 $* @Author : Feng* @Description : 观察者模式应用(C语言模拟C++)* @Explain : 热水器(被观察者)   water_heater洗澡模式(观察者)   washing_mode    50 < 热水器温度 < 70喝水模式(观察者)   drinking_mode   热水器温度 >= 100
**/#ifndef __WATERHEATER_H__
#define __WATERHEATER_H__#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "observer.h"/* 被观察者(热水器)类定义 */
struct water_heater {struct oble oble;   /* 继承被观察者基类 */int temprature;     /* 温度 */  int (*get)(struct water_heater *p_wheater);               /* 获取温度 */void (*set)(struct water_heater *p_wheater, int temp);    /* 设置温度 */
};/*** @创建热水器对象* @temp:温度 * @成功返回类对象,失败返回NULL 
**/
struct water_heater *new_water_heater(int temp);/* 观察者(洗澡模式)类定义 */
struct washing_mode {struct ober ober;
};/* 观察者(喝水模式)类定义 */
struct drinking_mode {struct ober ober;
};/*** @创建洗澡模式对象* @成功返回类对象,失败返回NULL 
**/
struct washing_mode *new_washing_mode(void);/*** @创建喝水模式对象* @成功返回类对象,失败返回NULL 
**/
struct drinking_mode *new_drinking_mode(void);#endif

 water_heater.c

/*** @Filename : water_heater.c* @Revision : $Revision: 1.0 $* @Author : Feng* @Description : 观察者模式应用(C语言模拟C++)* @Explain : 热水器(被观察者)   water_heater洗澡模式(观察者)   washing_mode    50 < 热水器温度 < 70喝水模式(观察者)   drinking_mode   热水器温度 >= 100
**/
#include "water_heater.h"/*** @获取热水器温度* @p_wheater:热水器类* @返回热水器温度 
**/
static int _get_temp(struct water_heater *p_wheater)
{return (p_wheater->temprature);
}/*** @设置热水器温度,并通知观察者* @p_wheater:热水器类      temp:温度 
**/
static void _set_temp(struct water_heater *p_wheater, int temp)
{p_wheater->temprature = temp;printf("current temprature is %d : ", p_wheater->temprature);p_wheater->oble.notify((struct oble *)p_wheater);printf("\n");
} /*** @创建热水器对象* @temp:温度 * @成功返回类对象,失败返回NULL 
**/
struct water_heater *new_water_heater(int temp)
{struct oble *p_ober;struct water_heater *p_wheater;p_wheater = (struct water_heater *)malloc(sizeof(struct water_heater));if (p_wheater == NULL)return NULL;memset((char *)p_wheater, 0, sizeof(struct water_heater));if ((p_ober = new_oble()) == NULL) {free(p_wheater);return NULL;}memcpy(&(p_wheater->oble), p_ober, sizeof(struct oble));free(p_ober);p_wheater->temprature = temp;p_wheater->get = _get_temp;p_wheater->set = _set_temp;return p_wheater;
}/*** @根据水温提示用户是否洗澡* @p_oble:被观察者类(热水器)
**/
static void _update_washing(struct ober *p_ober, struct oble *p_oble)
{struct water_heater *p_wheater = (struct water_heater *)p_oble;if ((p_wheater->get(p_wheater) > 50) && (p_wheater->get(p_wheater) < 70))printf("please washing...");
}/*** @根据水温提示用户是否喝水* @p_oble:被观察者类(热水器) 
**/
static void _update_drinking(struct ober *p_ober, struct oble *p_oble)
{struct water_heater *p_wheater = (struct water_heater *)p_oble;if (p_wheater->get(p_wheater) >= 100)printf("please drinking...");
}/*** @创建洗澡模式对象* @成功返回类对象,失败返回NULL 
**/
struct washing_mode *new_washing_mode(void)
{struct ober *p_ober;struct washing_mode *p_cwashingMode;p_cwashingMode = (struct washing_mode *)malloc(sizeof(struct washing_mode));if (p_cwashingMode == NULL)return NULL;memset((char *)p_cwashingMode, 0, sizeof(struct washing_mode));if ((p_ober = (struct ober *)malloc(sizeof(struct ober))) == NULL) {free(p_cwashingMode);return NULL;}p_ober->update = _update_washing;memcpy(&(p_cwashingMode->ober), p_ober, sizeof(struct ober));free(p_ober);return p_cwashingMode;
}/*** @创建喝水模式对象* @成功返回类对象,失败返回NULL 
**/
struct drinking_mode *new_drinking_mode(void)
{struct ober *p_ober;struct drinking_mode *p_cdrinkingMode;p_cdrinkingMode = (struct drinking_mode *)malloc(sizeof(struct drinking_mode));if (p_cdrinkingMode == NULL)return NULL;memset((char *)p_cdrinkingMode, 0, sizeof(struct drinking_mode));if ((p_ober = (struct ober *)malloc(sizeof(struct ober))) == NULL) {free(p_cdrinkingMode);return NULL;}p_ober->update = _update_drinking;memcpy(&(p_cdrinkingMode->ober), p_ober, sizeof(struct ober));free(p_ober);return p_cdrinkingMode;
}/*** @主函数,演示代码
**/
int main(void)
{   struct washing_mode *p_wash = new_washing_mode();struct drinking_mode *p_drink = new_drinking_mode();struct water_heater *p_water = new_water_heater(25);if ((p_water == NULL) || (p_wash == NULL) || (p_drink == NULL)) {printf("create observable class failed...\n");return -1;}p_water->oble.add(&(p_water->oble), &(p_wash->ober));p_water->oble.add(&(p_water->oble), &(p_drink->ober));/* 50-70 洗澡, >=100喝水 */p_water->set(p_water, 40);p_water->set(p_water, 60);p_water->set(p_water, 65);p_water->set(p_water, 120);  printf("--------------------------\n");  /* 删除喝水,水温等于120°不响应 */p_water->oble.rm(&(p_water->oble), &(p_drink->ober));p_water->set(p_water, 65);p_water->set(p_water, 120);printf("--------------------------\n"); /* 增加喝水,水温等于120°响应 */ p_water->oble.add(&(p_water->oble), &(p_drink->ober));p_water->set(p_water, 65);p_water->set(p_water, 120);return 0;
}

结论

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

feng:observer$ gcc -o water water_heater.c observer.c class_dll.c dll.c
feng:observer$ ./water
current temprature is 40 : 
current temprature is 60 : please washing...
current temprature is 65 : please washing...
current temprature is 120 : please drinking...
--------------------------
current temprature is 65 : please washing...
current temprature is 120 : 
--------------------------
current temprature is 65 : please washing...
current temprature is 120 : please drinking...
feng:observer$ 

分析:示例定义了热水器对象作为被观察者,同时定义了饮用模式和洗澡模式对象作为观察者,开始的时候,饮用模式和洗澡模式均监听热水器,所以当水温到达模式设定范围内时,自动触发相应的行为。一段时间后饮用模式不再监听热水器,所以无法触发饮水行为,再后来,饮用模式重新监听热水器,当水温到达设定范围时,又会自动触发饮用模式。

往期 · 推荐

浅谈linux - 字符设备框架

帮你自动化办公的python-自动提取pdf指定页(项目概述)

也没想象中那么神秘的数据结构-一种通用化的双向链表设计(底层源码)

也没想象中那么神秘的数据结构-一环扣一环的“链表”(双向链表)

我用C语言玩对象,偷偷关注着你的观察者模式(基类设计)

关注

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

这篇关于我用C语言玩对象,观察者模式应用2-热水的用途的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/200376

相关文章

Python结合PyWebView库打造跨平台桌面应用

《Python结合PyWebView库打造跨平台桌面应用》随着Web技术的发展,将HTML/CSS/JavaScript与Python结合构建桌面应用成为可能,本文将系统讲解如何使用PyWebView... 目录一、技术原理与优势分析1.1 架构原理1.2 核心优势二、开发环境搭建2.1 安装依赖2.2 验

Java字符串操作技巧之语法、示例与应用场景分析

《Java字符串操作技巧之语法、示例与应用场景分析》在Java算法题和日常开发中,字符串处理是必备的核心技能,本文全面梳理Java中字符串的常用操作语法,结合代码示例、应用场景和避坑指南,可快速掌握字... 目录引言1. 基础操作1.1 创建字符串1.2 获取长度1.3 访问字符2. 字符串处理2.1 子字

Python中判断对象是否为空的方法

《Python中判断对象是否为空的方法》在Python开发中,判断对象是否为“空”是高频操作,但看似简单的需求却暗藏玄机,从None到空容器,从零值到自定义对象的“假值”状态,不同场景下的“空”需要精... 目录一、python中的“空”值体系二、精准判定方法对比三、常见误区解析四、进阶处理技巧五、性能优化

SpringShell命令行之交互式Shell应用开发方式

《SpringShell命令行之交互式Shell应用开发方式》本文将深入探讨SpringShell的核心特性、实现方式及应用场景,帮助开发者掌握这一强大工具,具有很好的参考价值,希望对大家有所帮助,如... 目录引言一、Spring Shell概述二、创建命令类三、命令参数处理四、命令分组与帮助系统五、自定

SpringBoot应用中出现的Full GC问题的场景与解决

《SpringBoot应用中出现的FullGC问题的场景与解决》这篇文章主要为大家详细介绍了SpringBoot应用中出现的FullGC问题的场景与解决方法,文中的示例代码讲解详细,感兴趣的小伙伴可... 目录Full GC的原理与触发条件原理触发条件对Spring Boot应用的影响示例代码优化建议结论F

MySQL 分区与分库分表策略应用小结

《MySQL分区与分库分表策略应用小结》在大数据量、复杂查询和高并发的应用场景下,单一数据库往往难以满足性能和扩展性的要求,本文将详细介绍这两种策略的基本概念、实现方法及优缺点,并通过实际案例展示如... 目录mysql 分区与分库分表策略1. 数据库水平拆分的背景2. MySQL 分区策略2.1 分区概念

Spring Shell 命令行实现交互式Shell应用开发

《SpringShell命令行实现交互式Shell应用开发》本文主要介绍了SpringShell命令行实现交互式Shell应用开发,能够帮助开发者快速构建功能丰富的命令行应用程序,具有一定的参考价... 目录引言一、Spring Shell概述二、创建命令类三、命令参数处理四、命令分组与帮助系统五、自定义S

Go 语言中的select语句详解及工作原理

《Go语言中的select语句详解及工作原理》在Go语言中,select语句是用于处理多个通道(channel)操作的一种控制结构,它类似于switch语句,本文给大家介绍Go语言中的select语... 目录Go 语言中的 select 是做什么的基本功能语法工作原理示例示例 1:监听多个通道示例 2:带

C语言函数递归实际应用举例详解

《C语言函数递归实际应用举例详解》程序调用自身的编程技巧称为递归,递归做为一种算法在程序设计语言中广泛应用,:本文主要介绍C语言函数递归实际应用举例的相关资料,文中通过代码介绍的非常详细,需要的朋... 目录前言一、递归的概念与思想二、递归的限制条件 三、递归的实际应用举例(一)求 n 的阶乘(二)顺序打印

Linux系统配置NAT网络模式的详细步骤(附图文)

《Linux系统配置NAT网络模式的详细步骤(附图文)》本文详细指导如何在VMware环境下配置NAT网络模式,包括设置主机和虚拟机的IP地址、网关,以及针对Linux和Windows系统的具体步骤,... 目录一、配置NAT网络模式二、设置虚拟机交换机网关2.1 打开虚拟机2.2 管理员授权2.3 设置子