Chinaunix首页 | 论坛 | 博客
  • 博客访问: 405801
  • 博文数量: 48
  • 博客积分: 1820
  • 博客等级: 上尉
  • 技术积分: 705
  • 用 户 组: 普通用户
  • 注册时间: 2009-12-28 23:10
文章分类

全部博文(48)

文章存档

2012年(1)

2011年(12)

2010年(34)

2009年(1)

分类: LINUX

2010-12-28 22:39:00

问题描述:系统中的有些对象是由状态驱动的,它的行为与它的状态息息相关。一般这样的对象会被建模为状态机。当实现状态机的时候,无法避免要进行一系列的状态识别,从而引入一坨坨的if/else 或 switc/case,如果状态机的状态足够多,实现状态机的类将会变得相当的臃肿,并且代码的理解性会变得越来越差,当需求放生变化或增加新的功能时,修改这样的类变得非常的困难,更要命的是,对这样的类进行测试也非常的繁琐,尤其是修改状态类后进行回归也很头疼。前一阵子开发了一个系统,其中设计了一个状态机类,刚开始时只是使用了switch/case实现,后来增加了状态数量,也增加了逻辑,最后这个状态类充满了switch/case,维护起来越来越难了,所以进来学习了一下对状态机类的实现方法,今总结如下。

比如,针对游戏中的任务系统,任务可能拥有未接受、接受、拒绝、完成结束等状态,为方便讨论,暂且简化如下:


1task类的状态图

当对task 对象执行操作时,要经常的判断其状态到底满足不满足条件。以实现task对象为例,讨论一下状态机对象如何实现才能降低复杂度。比如对task 简单进行类设计如下:


2task 的类结构图

注:

这里忽略了task类的其他操作和属性,为简便讨论,我们只针对task类的Accept Reject 进行探讨即可。

刚开始的时候用如下的实现方式伪代码如下:

Function  Accepted()

Bengin
switch status

Case Unaccpted: 

{

Log("accept ok");

Return true;

}

Case Accpted:

{

Log("accept already");

Return false;

}


  End

简单约定:

客户端:对状态类的对象的使用者,即会调用状态类对象的类。

主对象:被建模为状态机类的对象,这里就是task

状态对象:只实现了状态机类的特定状态的行为,比如实现了一个主负责task Accepted状态下的操作的类,这种在此称为状态对象(在此就混淆一下类和对象 的概念啦)。

思路一:

利用状态对象:封装和状态相关的操作到特定的类中,无论何时客户端调用模态对象的某个行为,对象将方法分派给相应的状态类,当状态发生改变时,改变相应的状态对象即可。

类机构如下图:


2:使用状态对象的类结构

示例代码

Accept 接口为例:

Class Task_t:

int accept()

{

state_i* state = current_state();

if (true == state->handle_accept(task_data))

{

next_state();

}

}


Class state_unaccepted_t:

bool handle_accept()

{

return true;

}

bool handle_reject)

{

return false;

}


Class state_accepted_t:

bool handle_accept()

{

return false;

}

bool handle_reject)

{

return true;

}


优点:

将于状态相关的行为封装到特定的实现中,使得修改和扩展状态行为变得非常简单,状态类的实现是状态无关的,它接受主对象的实例数据作为参数。

缺点:

状态和状态相关的行为较少时,显得有点事倍功半,引入了不少类。

思路二:

有些场合会将相同的状态统一分类,当某一事件触发时,会引发这一类对象的相关操作。这种情况适合使用状态集合管理状态类。

伪代码示例:

Void do_xx()

Begin

##处于A状态的每个对象。

Foreach  object in collection_state_A:

Object.do_xx()

collection_state_A.remove(Object)

collection_state_B.add(Object)

End


阅读(3035) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~