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

概述

状态模式允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类。

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

示例

★背景说明:水包含三种状态,固态、液态、气态,而三种状态根据温度决定,不同温度对应不同状态,当改变水温,对应的状态将会自行改变。 

★环境对象(water):

属性:温度(当前水温)

行为:获取温度、设置温度、提高温度、降低温度、处理函数。

继承:继承环境类context基类

★状态对象(固态、液态、气态,每种状态单例设计):

属性:无

行为:无。

继承:继承状态类state基类

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

 water.h

/**
 * @Filename : water.h
 * @Revision : $Revision: 1.0 $
 * @Author : Feng(微信公众号:不只会拍照的程序猿)
 * @Description : 状态模式基类实现(C语言模拟C++)
 * @Explain : 水包含三种状态
             气态  temp>=100    liquid  单例模式
             固态  temp<=0       solid    单例模式
             液态  0<temp<100  gas       单例模式
**/
#ifndef __WATER_H__
#define __WATER_H__

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

/* water类定义 */
struct water {
    struct context context; /* 继承当前状态基类 */       
    int temprature;         /* 温度 */ 

    int (*get)(struct water *p_water);                  /* 获取温度 */
    void (*set)(struct water *p_water, int temp);       /* 设置温度 */
    void (*rise)(struct water *p_water, int temp);      /* 提高温度 */
    void (*reduce)(struct water *p_water, int temp);    /* 降低温度 */
    void (*handle)(struct water *p_water);              /* 处理函数 */  
};

/**
 * @创建water对象
 * @temp:温度 
 * @成功返回类对象,失败返回NULL 
**/
struct water *new_water(int temp);

/* 固态类定义 */
struct solid {
    struct state state;
};

/* 液态类定义 */
struct liquid {
    struct state state;
};

/* 气态类定义 */
struct gas {
    struct state state;
};

/**
 * @创建固态对象
 * @name:类名
 * @成功返回类对象,失败返回NULL 
**/
struct solid *new_solid(char *name);

/**
 * @创建液态对象
 * @name:类名
 * @成功返回类对象,失败返回NULL 
**/
struct liquid *new_liquid(char *name);

/**
 * @创建气态对象
 * @name:类名
 * @成功返回类对象,失败返回NULL 
**/
struct gas *new_gas(char *name);

#endif

 water.c

/**
 * @Filename : water.c
 * @Revision : $Revision: 1.0 $
 * @Author : Feng(微信公众号:不只会拍照的程序猿)
 * @Description : 状态模式基类实现(C语言模拟C++)
 * @Explain : 水包含三种状态
             气态  temp>=100   liquid  单例模式
             固态  temp<=0       solid   单例模式
             液态  0<temp<100  gas      单例模式
**/

#include "water.h"

/**
 * @获取水温
 * @p_water:water类
 * @返回温度
**/
static int _get(struct water *p_water)
{
    struct context *p_context = (struct context *)p_water;  
    return (*(int *)CLASS_CALL_0(p_context, get_info));
}

/**
 * @设置温度
 * @p_water:water类      temp:温度
**/
static void _set(struct water *p_water, int temp)
{
    struct context *p_context = (struct context *)p_water;
    int *p_tmp = (int *)CLASS_CALL_0(p_context, get_info);

    if (p_tmp == NULL)
        p_tmp = (int *)malloc(sizeof(int));

    *p_tmp = temp;    
    CLASS_CALL(p_context, set_info, (void *)p_tmp);
} 

/**
 * @提高温度
 * @p_water:water类      temp:温度
**/
static void _rise(struct water *p_water, int temp)
{  
    CLASS_CALL(p_water, set, CLASS_CALL_0(p_water, get) + temp);
} 

/**
 * @降低温度
 * @p_water:water类      temp:温度
**/
static void _reduce(struct water *p_water, int temp)
{
    CLASS_CALL(p_water, set, CLASS_CALL_0(p_water, get) - temp);
}           

/**
 * @处理函数
 * @p_water:water类
**/
static void _handle(struct water *p_water)
{
    /* 获取当前状态 */
    struct state *p_state = p_water->context.get(&(p_water->context));

    /* 根据当前状态执行相对应的状态处理函数 */
    if (CLASS_CALL(p_water->context.p_dll, find_key, p_state) != NULL)
        CLASS_CALL(p_state, handle, (struct context *)p_water);
} 

/**
 * @创建water对象
 * @temp:温度 
 * @成功返回类对象,失败返回NULL 
**/
struct water *new_water(int temp)
{
    struct context *p_context;
    struct water *p_water;

    p_water = (struct water *)malloc(sizeof(struct water));

    if (p_water == NULL)
        return NULL;

    memset((char *)p_water, 0, sizeof(struct water));

    if ((p_context = new_context()) == NULL) {
        free(p_water);
        return NULL;
    }
    memcpy(&(p_water->context), p_context, sizeof(struct context));
    free(p_context);

    p_water->temprature = temp;
    p_water->get = _get;
    p_water->set = _set;
    p_water->rise = _rise;
    p_water->reduce = _reduce;    
    p_water->handle = _handle;

    p_water->set(p_water, temp);
    return p_water;
}

/**
 * @不同状态下的执行函数,实际应用中可分开写
 * @p_state:状态类          p_context:环境类
 * @返回当前状态
**/
static void _state_handle(struct state *p_state, struct context *p_context)
{
    printf("my state is %s, the temprature is %d\n", 
                p_state->name, *(int *)p_context->p_info);
}

/**
 * @固态匹配判断
 * @p_state:状态类          p_context:环境类
 * @匹配返回0,否则返回-1
**/
static int _solid_match(struct state *p_state, struct context *p_context)
{
    int tmp = *(int *)(p_context->p_info);
    return (tmp < 0 ? 0 : -1);
} 

/**
 * @气态匹配判断
 * @p_state:状态类          p_context:环境类
 * @匹配返回0,否则返回-1
**/
static int _gas_match(struct state *p_state, struct context *p_context)
{
    int tmp = *(int *)(p_context->p_info);
    return (tmp > 100 ? 0 : -1);
}

/**
 * @液态匹配判断
 * @p_state:状态类          p_context:环境类
 * @匹配返回0,否则返回-1
**/
static int _liquid_match(struct state *p_state, struct context *p_context)
{
    int tmp = *(int *)(p_context->p_info);
    return (((tmp >= 0) && (tmp <= 100)) ? 0 : -1);
}

/**
 * @获取状态名
 * @p_state:状态类
 * @返回当前状态名
**/
static char *_get_name(struct state *p_state)
{
    return (p_state->name);
} 

/**
 * @创建固态对象
 * @name:类名
 * @成功返回类对象,失败返回NULL 
**/
struct solid *new_solid(char *name)
{
    struct state *p_state;
    static struct solid *p_solid = NULL;

    if (p_solid != NULL)
        return p_solid;

    p_solid = (struct solid *)malloc(sizeof(struct solid));

    if (p_solid == NULL)
        return NULL;

    memset((char *)p_solid, 0, sizeof(struct solid));

    if ((p_state = (struct state *)malloc(sizeof(struct state))) == NULL) {
        free(p_solid);
        return NULL;
    }
    strcpy(p_state->name, name);
    p_state->get_name = _get_name;
    p_state->match = _solid_match;
    p_state->handle = _state_handle;
    memcpy(&(p_solid->state), p_state, sizeof(struct state));
    free(p_state);

    return p_solid;
}

/**
 * @创建液态对象
 * @name:类名
 * @成功返回类对象,失败返回NULL 
**/
struct liquid *new_liquid(char *name)
{
    struct state *p_state;
    static struct liquid *p_liquid = NULL;

    if (p_liquid != NULL)
        return p_liquid;

    p_liquid = (struct liquid *)malloc(sizeof(struct liquid));

    if (p_liquid == NULL)
        return NULL;

    memset((char *)p_liquid, 0, sizeof(struct liquid));

    if ((p_state = (struct state *)malloc(sizeof(struct state))) == NULL) {
        free(p_liquid);
        return NULL;
    }
    strcpy(p_state->name, name);
    p_state->get_name = _get_name;
    p_state->match = _liquid_match;
    p_state->handle = _state_handle;
    memcpy(&(p_liquid->state), p_state, sizeof(struct state));
    free(p_state);

    return p_liquid;
}

/**
 * @创建气态对象
 * @name:类名
 * @成功返回类对象,失败返回NULL 
**/
struct gas *new_gas(char *name)
{
    struct state *p_state;
    static struct gas *p_gas = NULL;

    if (p_gas != NULL)
        return p_gas;

    p_gas = (struct gas *)malloc(sizeof(struct gas));

    if (p_gas == NULL)
        return NULL;

    memset((char *)p_gas, 0, sizeof(struct gas));

    if ((p_state = (struct state *)malloc(sizeof(struct state))) == NULL) {
        free(p_gas);
        return NULL;
    }
    strcpy(p_state->name, name);
    p_state->get_name = _get_name;
    p_state->match = _gas_match;
    p_state->handle = _state_handle;
    memcpy(&(p_gas->state), p_state, sizeof(struct state));
    free(p_state);

    return p_gas;
}

/**
 * @主函数,演示代码 
**/
int main(void)
{ 
    struct water *p_water = new_water(25);
    struct solid *p_solid = new_solid("solid");
    struct liquid *p_liquid = new_liquid("liquid");
    struct gas *p_gas = new_gas("gas");

    p_water->context.add((struct context *)p_water, (struct state *)p_solid);
    p_water->context.add((struct context *)p_water, (struct state *)p_liquid);
    p_water->context.add((struct context *)p_water, (struct state *)p_gas);

    CLASS_CALL_0(p_water, handle);      /* 默认25°,液态 */
    printf("---------------------------------------\n");
    CLASS_CALL(p_water, set, -4);
    CLASS_CALL_0(p_water, handle);      /* -4°,固态 */
    printf("---------------------------------------\n");
    CLASS_CALL(p_water, rise, 18);      
    CLASS_CALL_0(p_water, handle);      /* -4 + 18 = 14°,液态 */
    printf("---------------------------------------\n");
    CLASS_CALL(p_water, rise, 110);
    CLASS_CALL_0(p_water, handle);      /* 14 + 110 = 124°,气态 */
    printf("---------------------------------------\n");
    CLASS_CALL(p_water, reduce, 80);    
    CLASS_CALL_0(p_water, handle);      /* 124 - 80 = 44°,液态 */
    printf("---------------------------------------\n");
    CLASS_CALL(p_water, reduce, 80);
    CLASS_CALL_0(p_water, handle);      /* 44 - 80 = -36°,固态 */

    return 0;
}

结论

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

feng:state$ gcc -o water water.c state.c class_dll.c dll.c
feng:state$ ./water
---------------------------------------
init state : solid
my state is solid, the temprature is -4
---------------------------------------
state: solid change to state : liquid
my state is liquid, the temprature is 14
---------------------------------------
state: liquid change to state : gas
my state is gas, the temprature is 124
---------------------------------------
state: gas change to state : liquid
my state is liquid, the temprature is 44
---------------------------------------
state: liquid change to state : solid
my state is solid, the temprature is -36
feng:state$ 

分析:示例定义了water对象作为环境类,同时定义了liquid(液态)、solid(固态)、gas(气态)和speed(快进)四种状态对象,状态之间通过温度的变化进行响应的转换。

关注

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

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

不只会拍照的程序猿

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

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

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

打赏作者

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

抵扣说明:

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

余额充值