states模式在C语言中的实践
2007-11-20 15:58
176 查看
最近开发一个项目的状态机,由于状态比较多,外部事件也比较复杂,用传统的方法状态机相当臃肿,可读性和调试起来比较困难,看过设计模式那本书中有提及states模式,一直没有实践过,这次就在这个项目中试了试,效果那是相当好啊,看来把面向对象坚持到底好处多多啊。
先来说说C中的面向对象,其实和C++类似,主要表现在设计思想上,对业务进行功能划分,分析得到各个独立对象,给各个对象建立行为,封装接口,尽量减少对象间的耦合性。在具体的代码阶段,用函数指针实现继承关系。这次用socket主动连接的状态机来举例说明.
一个简单的主动式socket在运行态划分为三个状态,IDLE状态表示没有进行连接空闲,CONNECTING状态表示正在连接状态,READY状态表示已经建立连接可以通讯。在整个socket通讯期间可能发生的外部事件有CONNCNF连接确认,DISCIND连接断开,DATAIND数据到达,SEND发送数据,CONNREQ连接请求等。下表分别列出在三种状态下各个事件可能的处理行为。
States模式主要的特点是将socket各个状态升级为一个对象,它不仅仅是一个状态,它还封装了在该状态下,socket可能的行为。
首先定义一个states基类,其包含所有状态下socket可能的行为:
struct SockStates {
void *implementer; // 用来指向states实例的实现者
s32 (*connReq)(SockStates* _me, void* dstAddr, int addrLen);
s32 (*connCnf)(SockStates* _me);
s32 (*discInd)(SockStates* _me, int cause);
s32 (*dataInd)(SockStates* _me, void* data, int dataLen);
s32 (*writeAble)(SockStates* _me);
s32 (*send)(SockStates* _me, void* data, int dataLen);
void (*destroy)(SockStates* _me);
} ;
在Socket对象中使用SockStates对象来表示特定的状态
struct Socket ...{
SockStates* states;
// …………………
}
当socket发生外部事件的时候,直接调用states中的行为完成处理,socket对象实际上不关心到底是在什么状态下怎么处理这些事件,而都交给states的子类来实现。socket本身只需要一个提供一个改变自身状态的接口。
void Socket_changeStates(Socket * me, SockStates * states)
{
// 删除原来的状态对象
if(me->states)
me->states->destroy(me->states);
// 改变为新的状态对象
me->states = states;
}
// 外部事件发生时调用的接口
void Socket_connReq(Socket* me, void* dstAddr, int addrLen)
{
// 如果当前状态下有对connReq的处理则调用,没有则什么对不做,或者报错
If (me->states && me-> me->states->connReq)
me->states->connReq(me->states, dstAddr, addrLen);
}
其它操作(connCnf, discInd, dataInd, writeable, send)与connReq同样形式封装。
然后分别实现具体的状态对象:
// IDLE状态对象
typedef struct SocketIdleStates ...{
SockStates states;
Socket* sock;
// …………………………
} SocketIdleStates;
// Idle 状态下connReq的处理
void SocketIdleStates_connReq(SockStates * _me, void* dstAddr, int addrLen)
{
SocketIdleStates* me = (SocketIdleStates*)_me->implementer;
// 调用接口完成连接请求
// 切换socket状态到CONNECTING
Socket_changeStates(me->sock, SocketConnectingStates_create(me->sock));
}
void SocketIdleStates_destroy(SockStates* _me)
{
SocketIdleStates * me = (SocketIdleStates*)_me->implementer;
free (me);
}
SockStates * SocketIdleStates_create(Socket * usr)
{
SocketIdleStates * me;
me = (SocketIdleStates*)malloc(sizeof(SocketIdleStates));
assert(me);
me->states.implementer = me;
me->states.destroy = SocketIdleStates_destroy;
me->states.connReq = SocketIdleStates_connReq;
me->sock = usr;
return &me->states;
}
// CONNECTING状态对象
typedef struct SocketConnectingStates ...{
SockStates states;
Socket* sock;
// …………………………
} SocketIdleStates;
// Connecting 状态下connCnf的处理
void SocketConnectingStates_connCnf(SockStates * _me)
{
SocketConnectingStates* me = (SocketConnectingStates*)_me->implementer;
// 调用接口完成连接确认
// 切换socket状态到READY
Socket_changeStates(me->sock, SocketReadyStates_create(me->sock));
}
// Connecting 状态下discInd的处理
void SocketConnectingStates_discInd(SockStates * _me, int cause)
{
SocketConnectingStates* me = (SocketConnectingStates*)_me->implementer;
// 调用接口完成断开连接操作
// 切换socket状态到IDLE
Socket_changeStates(me->sock, SocketIdleStates_create(me->sock));
}
void SocketConnectingStates_destroy(SockStates* _me)
{
SocketConnectingStates * me = (SocketConnectingStates *)_me->implementer;
free (me);
}
SockStates * SocketConnectingStates_create(Socket * usr)
{
SocketConnectingStates * me;
me = (SocketConnectingStates *)malloc(sizeof(SocketConnectingStates));
assert(me);
me->states.implementer = me;
me->states.destroy = SocketConnectingStates_destroy;
me->states.connCnf = SocketConnectingStates_connCnf;
me->states.discInd = SocketConnectingStates_discInd;
me->sock = usr;
return &me->states;
}
// READY状态对象
typedef struct SocketReadyStates ...{
SockStates states;
Socket* sock;
// …………………………
} SocketReadyStates;
// ready状态下send的处理
void SocketReadyStates_send(SockStates * _me, void* data, int dataLen)
{
SocketReadyStates * me = (SocketReadyStates *)_me->implementer;
// 调用接口发送数据
}
// ready状态下dataInd的处理
void SocketReadyStates_dataInd(SockStates * _me, void* data, int dataLen)
{
SocketReadyStates * me = (SocketReadyStates *)_me->implementer;
// 调用接口处理收到的数据
}
// ready状态下discInd的处理
void SocketReadyStates_discInd(SockStates * _me, int cause)
{
SocketReadyStates * me = (SocketReadyStates *)_me->implementer;
// 调用接口完成断开连接操作
// 切换socket状态到IDLE
Socket_changeStates(me->sock, SocketIdleStates_create(me->sock));
}
void SocketReadyStates_destroy(SockStates* _me)
{
SocketReadyStates * me = (SocketReadyStates *)_me->implementer;
free (me);
}
SockStates * SocketReadyStates_create(Socket * usr)
{
SocketReadyStates * me;
me = (SocketReadyStates *)malloc(sizeof(SocketReadyStates));
assert(me);
me->states.implementer = me;
me->states.destroy = SocketReadyStates_destroy;
me->states.send = SocketReadyStates_send;
me->states.dataInd = SocketReadyStates_dataInd;
me->states.discInd = SocketReadyStates_discInd;
me->sock = usr;
return &me->states;
}
这样整个socket的行为被各个状态子类瓜分了,切换和操作都在各个子类去完成,socket只负责向外部提供接口,虽然看起来比较复杂,但当状态很多,外部事件很多的时候,逻辑相当清楚,扩展起来需要添加减少状态也相当的方便,不会影响其他状态下的行为。
先来说说C中的面向对象,其实和C++类似,主要表现在设计思想上,对业务进行功能划分,分析得到各个独立对象,给各个对象建立行为,封装接口,尽量减少对象间的耦合性。在具体的代码阶段,用函数指针实现继承关系。这次用socket主动连接的状态机来举例说明.
一个简单的主动式socket在运行态划分为三个状态,IDLE状态表示没有进行连接空闲,CONNECTING状态表示正在连接状态,READY状态表示已经建立连接可以通讯。在整个socket通讯期间可能发生的外部事件有CONNCNF连接确认,DISCIND连接断开,DATAIND数据到达,SEND发送数据,CONNREQ连接请求等。下表分别列出在三种状态下各个事件可能的处理行为。
[align=left] [/align] | [align=left]IDLE[/align] | [align=left]CONNECTING[/align] | [align=left]READY[/align] |
[align=left]CONNREQ[/align] | [align=left]Do connect request,[/align] [align=left]states change to CONNECTING[/align] | [align=left]Nothing[/align] | [align=left]Nothing[/align] |
[align=left]CONNCNF[/align] | [align=left]Nothing[/align] | [align=left]Socket ready, states change to READY[/align] | [align=left]Nothing[/align] |
[align=left]DISCIND[/align] | [align=left]Nothing[/align] | [align=left]Connect failed, states change to IDLE[/align] | [align=left]Connection lost, states change to IDLE[/align] |
[align=left]DATAIND[/align] | [align=left]Nothing[/align] | [align=left]Nothing[/align] | [align=left]Data coming[/align] |
[align=left]SEND[/align] | [align=left]Nothing[/align] | [align=left]Nothing[/align] | [align=left]Send data[/align] |
首先定义一个states基类,其包含所有状态下socket可能的行为:
struct SockStates {
void *implementer; // 用来指向states实例的实现者
s32 (*connReq)(SockStates* _me, void* dstAddr, int addrLen);
s32 (*connCnf)(SockStates* _me);
s32 (*discInd)(SockStates* _me, int cause);
s32 (*dataInd)(SockStates* _me, void* data, int dataLen);
s32 (*writeAble)(SockStates* _me);
s32 (*send)(SockStates* _me, void* data, int dataLen);
void (*destroy)(SockStates* _me);
} ;
在Socket对象中使用SockStates对象来表示特定的状态
struct Socket ...{
SockStates* states;
// …………………
}
当socket发生外部事件的时候,直接调用states中的行为完成处理,socket对象实际上不关心到底是在什么状态下怎么处理这些事件,而都交给states的子类来实现。socket本身只需要一个提供一个改变自身状态的接口。
void Socket_changeStates(Socket * me, SockStates * states)
{
// 删除原来的状态对象
if(me->states)
me->states->destroy(me->states);
// 改变为新的状态对象
me->states = states;
}
// 外部事件发生时调用的接口
void Socket_connReq(Socket* me, void* dstAddr, int addrLen)
{
// 如果当前状态下有对connReq的处理则调用,没有则什么对不做,或者报错
If (me->states && me-> me->states->connReq)
me->states->connReq(me->states, dstAddr, addrLen);
}
其它操作(connCnf, discInd, dataInd, writeable, send)与connReq同样形式封装。
然后分别实现具体的状态对象:
// IDLE状态对象
typedef struct SocketIdleStates ...{
SockStates states;
Socket* sock;
// …………………………
} SocketIdleStates;
// Idle 状态下connReq的处理
void SocketIdleStates_connReq(SockStates * _me, void* dstAddr, int addrLen)
{
SocketIdleStates* me = (SocketIdleStates*)_me->implementer;
// 调用接口完成连接请求
// 切换socket状态到CONNECTING
Socket_changeStates(me->sock, SocketConnectingStates_create(me->sock));
}
void SocketIdleStates_destroy(SockStates* _me)
{
SocketIdleStates * me = (SocketIdleStates*)_me->implementer;
free (me);
}
SockStates * SocketIdleStates_create(Socket * usr)
{
SocketIdleStates * me;
me = (SocketIdleStates*)malloc(sizeof(SocketIdleStates));
assert(me);
me->states.implementer = me;
me->states.destroy = SocketIdleStates_destroy;
me->states.connReq = SocketIdleStates_connReq;
me->sock = usr;
return &me->states;
}
// CONNECTING状态对象
typedef struct SocketConnectingStates ...{
SockStates states;
Socket* sock;
// …………………………
} SocketIdleStates;
// Connecting 状态下connCnf的处理
void SocketConnectingStates_connCnf(SockStates * _me)
{
SocketConnectingStates* me = (SocketConnectingStates*)_me->implementer;
// 调用接口完成连接确认
// 切换socket状态到READY
Socket_changeStates(me->sock, SocketReadyStates_create(me->sock));
}
// Connecting 状态下discInd的处理
void SocketConnectingStates_discInd(SockStates * _me, int cause)
{
SocketConnectingStates* me = (SocketConnectingStates*)_me->implementer;
// 调用接口完成断开连接操作
// 切换socket状态到IDLE
Socket_changeStates(me->sock, SocketIdleStates_create(me->sock));
}
void SocketConnectingStates_destroy(SockStates* _me)
{
SocketConnectingStates * me = (SocketConnectingStates *)_me->implementer;
free (me);
}
SockStates * SocketConnectingStates_create(Socket * usr)
{
SocketConnectingStates * me;
me = (SocketConnectingStates *)malloc(sizeof(SocketConnectingStates));
assert(me);
me->states.implementer = me;
me->states.destroy = SocketConnectingStates_destroy;
me->states.connCnf = SocketConnectingStates_connCnf;
me->states.discInd = SocketConnectingStates_discInd;
me->sock = usr;
return &me->states;
}
// READY状态对象
typedef struct SocketReadyStates ...{
SockStates states;
Socket* sock;
// …………………………
} SocketReadyStates;
// ready状态下send的处理
void SocketReadyStates_send(SockStates * _me, void* data, int dataLen)
{
SocketReadyStates * me = (SocketReadyStates *)_me->implementer;
// 调用接口发送数据
}
// ready状态下dataInd的处理
void SocketReadyStates_dataInd(SockStates * _me, void* data, int dataLen)
{
SocketReadyStates * me = (SocketReadyStates *)_me->implementer;
// 调用接口处理收到的数据
}
// ready状态下discInd的处理
void SocketReadyStates_discInd(SockStates * _me, int cause)
{
SocketReadyStates * me = (SocketReadyStates *)_me->implementer;
// 调用接口完成断开连接操作
// 切换socket状态到IDLE
Socket_changeStates(me->sock, SocketIdleStates_create(me->sock));
}
void SocketReadyStates_destroy(SockStates* _me)
{
SocketReadyStates * me = (SocketReadyStates *)_me->implementer;
free (me);
}
SockStates * SocketReadyStates_create(Socket * usr)
{
SocketReadyStates * me;
me = (SocketReadyStates *)malloc(sizeof(SocketReadyStates));
assert(me);
me->states.implementer = me;
me->states.destroy = SocketReadyStates_destroy;
me->states.send = SocketReadyStates_send;
me->states.dataInd = SocketReadyStates_dataInd;
me->states.discInd = SocketReadyStates_discInd;
me->sock = usr;
return &me->states;
}
这样整个socket的行为被各个状态子类瓜分了,切换和操作都在各个子类去完成,socket只负责向外部提供接口,虽然看起来比较复杂,但当状态很多,外部事件很多的时候,逻辑相当清楚,扩展起来需要添加减少状态也相当的方便,不会影响其他状态下的行为。
相关文章推荐
- 5.5 进入编辑模式 5.6 vim命令模式 5.7 vim实践
- C语言 设计模式之访问者模式
- C语言和设计模式(外观模式)
- 小议大小端模式对C语言的共用体结构的影响
- C语言插件开发模式
- c语言编程--网络编程模式
- C语言 算法"KMP" 查找字符串 ”模式匹配“
- 《敏捷软件开发-原则、模式与实践》-第七章 什么是敏捷设计
- 《敏捷软件开发-原则、模式与实践》-第八章 单一职责原则(SRP)
- 小议大小端模式对C语言的共用体结构的影响
- 代理模式之动态代理实践
- C语言中文件打开模式(r/w/a/r+/w+/a+/rb/wb/ab/rb+/wb+/ab+)浅析
- 一种寄生型设计模式在 Swing 应用开发中的实践
- 《C语言及程序设计》实践项目——用循环处理文字
- JNA调用C语言动态链接库学习实践总结
- c语言fopen追加模式下fseek失效
- Page Object设计模式实践
- 第十次c语言上机实践操作
- 走向.NET架构设计—第五章—业务层模式,原则,实践(前篇)
- 单例模式 (C语言实现)