概述
状态模式允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类。
之前的文章已经详细阐述了这种设计模式的核心和注意事项,并完成了基类设计,请参见《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语言、嵌入式、编程相关知识,也会抽空分享些摄影相关内容,同样也分享大量摄影、编程相关视频和源码,另外你若想要本文章源码请关注公众号:不只会拍照的程序猿,后台回复:设计模式源码,也可点击此处下载。