states模式在C语言中的实践

来源:互联网 发布:手机软件恢复软件下载 编辑:程序博客网 时间:2024/04/28 02:25
最近开发一个项目的状态机,由于状态比较多,外部事件也比较复杂,用传统的方法状态机相当臃肿,可读性和调试起来比较困难,看过设计模式那本书中有提及states模式,一直没有实践过,这次就在这个项目中试了试,效果那是相当好啊,看来把面向对象坚持到底好处多多啊。
先来说说C中的面向对象,其实和C++类似,主要表现在设计思想上,对业务进行功能划分,分析得到各个独立对象,给各个对象建立行为,封装接口,尽量减少对象间的耦合性。在具体的代码阶段,用函数指针实现继承关系。这次用socket主动连接的状态机来举例说明.
一个简单的主动式socket在运行态划分为三个状态,IDLE状态表示没有进行连接空闲,CONNECTING状态表示正在连接状态,READY状态表示已经建立连接可以通讯。在整个socket通讯期间可能发生的外部事件有CONNCNF连接确认,DISCIND连接断开,DATAIND数据到达,SEND发送数据,CONNREQ连接请求等。下表分别列出在三种状态下各个事件可能的处理行为。
 
 
IDLE
CONNECTING
READY
CONNREQ
Do connect request,
states change to CONNECTING
Nothing
Nothing
CONNCNF
Nothing
Socket ready, states change to READY
Nothing
DISCIND
Nothing
Connect failed, states change to IDLE
Connection lost, states change to IDLE
DATAIND
Nothing
Nothing
Data coming
SEND
Nothing
Nothing
Send data
 
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只负责向外部提供接口,虽然看起来比较复杂,但当状态很多,外部事件很多的时候,逻辑相当清楚,扩展起来需要添加减少状态也相当的方便,不会影响其他状态下的行为。
   
原创粉丝点击