我用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语言、嵌入式、编程相关知识,也会抽空分享些摄影相关内容,同样也分享大量摄影、编程相关视频和源码,另外你若想要本文章源码请关注公众号:不只会拍照的程序猿,后台回复:设计模式源码,也可点击此处下载

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不只会拍照的程序猿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值