C# 3.0下有限状态机的一种优雅的实现
C# 3.0下有限状态机的一种优雅的实现
实现状态机有多种模式,其中最灵活而强大的方式是通过迁移表来实现,该方式的缺点之一是需要编写大量小块代码去支持迁移表。而在C#3.0中,可以以一种非常优雅的方式实现。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace StateMachine
{
class Program
{
static void Main(string[] args)
{
var door = new Door(State.Open);
while (true)
{
string s = Console.ReadLine();
Operation op = string.IsNullOrEmpty(s) ? Operation.Push : Operation.Pull;
door.Process(op);
}
}
}
enum Operation
{
Push, Pull
}
enum State
{
Open, Closed
}
class Door
{
public State State { get; set; }
Dictionary<State, Dictionary<Operation, Action>> rule;
public Door(State state)
{
this.State = state;
rule = new Dictionary<State, Dictionary<Operation, Action>>();
foreach (var e in Enum.GetValues(typeof(State)))
{
rule[(State)e] = new Dictionary<Operation, Action>();
}
InitOperationRule();
}
void InitOperationRule()
{
//正常操作
rule[State.Closed][Operation.Push] = () => { Console.WriteLine("门被推开了"); State = State.Open; };
rule[State.Open][Operation.Pull] = () => { Console.WriteLine("门被拉上了"); State = State.Closed; };
加入几种特殊情况的处理
//rule[State.Closed][Operation.Pull] = () => Console.WriteLine("门是关上的,拉了也白拉");
//rule[State.Open][Operation.Push] = () => Console.WriteLine("门是开的,不用推了,直接进去吧");
}
public void Process(Operation op)
{
try
{
rule[State][op]();
}
catch (KeyNotFoundException)
{
Console.WriteLine(string.Format("门在{0}状态下不允许{1}操作", State, op));
}
}
}
}
从代码中可以看到,通过lambda表达式,可以简化迁移表的构造,并且更加直观。
通过迁移表构造状态机的一种不足在于查询速度,在本例中每个操作都要进行两次查询才能进行状态转换操作。如果状态较多则非常费时,这里我把它改进了一下,使得每次操作只需要查询一次即可。
class DoorPlus
{
State state;
public State State
{
get { return state; }
set
{
if (state != value)
currentOpRule = rule[value];
state = value;
}
}
Dictionary<Operation, Action> currentOpRule;
Dictionary<State, Dictionary<Operation, Action>> rule;
public DoorPlus(State state)
{
this.State = state;
rule = new Dictionary<State, Dictionary<Operation, Action>>();
foreach (var e in Enum.GetValues(typeof(State)))
{
rule[(State)e] = new Dictionary<Operation, Action>();
}
currentOpRule = rule[State];
InitOperationRule();
}
void InitOperationRule()
{
//正常操作
rule[State.Closed][Operation.Push] = () => { Console.WriteLine("门被推开了"); State = State.Open; };
rule[State.Open][Operation.Pull] = () => { Console.WriteLine("门被拉上了"); State = State.Closed; };
加入几种特殊情况的处理
//rule[State.Closed][Operation.Pull] = () => Console.WriteLine("门是关上的,拉了也白拉");
//rule[State.Open][Operation.Push] = () => Console.WriteLine("门是开的,不用推了,直接进去吧");
}
public void Process(Operation op)
{
try
{
currentOpRule[op]();
}
catch (KeyNotFoundException)
{
Console.WriteLine(string.Format("门在{0}状态下不允许{1}操作", State, op));
}
}
}
C# 3.0下有限状态机的一种优雅的实现相关推荐
- Linux下MySQL的几种安装方式
闲来有空,整理下Linux下Mysql的几种安装方式,分别使用yum/rpm.常规方式编译安装.cmake方式编译安装以及使用二进制方式免编译安装MySQL Linux系统环境: CentOS rel ...
- [RHEL] RHEL7.0 下 Postfix + Dovecot 实现邮件发送
RHEL7.0 下 Postfix + Dovecot 实现邮件发送 一.前言 大家都对邮件服务(mail service)很感兴趣嘛.我在自己 博客站 预言了自己会实战一次,访问量一天到十几(毕竟平 ...
- 【Android 逆向】ART 脱壳 ( InMemoryDexClassLoader 脱壳 | 加固厂商在 ART 下使用的两种类加载器 | InMemoryDexClassLoader 源码 )
文章目录 一.加固厂商在 ART 下使用的两种类加载器 ( InMemoryDexClassLoader | DexClassLoader ) 二.InMemoryDexClassLoader 源码分 ...
- CE6.0 下获得 SD 卡序列号的方法
经常在坛子里看到讨论软件加密的帖子,纯软件加密与读取硬件序列号加密是经常讨论到的. 两种方法各有优缺点. 在通过读取硬件序列号的方法来加密的方法,受硬件的限制. 一般来说,CPU和T-Flash可能存 ...
- android6.0源码分析之Camera API2.0下的Preview(预览)流程分析
1.Camera2 preview的应用层流程分析 preview流程都是从startPreview开始的,所以来看startPreview方法的代码: <code class="hl ...
- 深入讲解JSP 2.0下的动态内容缓存技术
深入讲解JSP 2.0下的动态内容缓存技术 来源: 山里娃信息网 新闻题要: 内容缓存是Web应用中最普通的优化技术之一,例如,可以使用一个自定义地JSP标签--我们将之命名为<jc:cach ...
- 关于.Net2.0下配置架构的使用
上次用到配置文件,就花了一些时间研究了一下.Net2.0下的配置文件架构,当时感觉确实很强大,完善,但看的有些头晕.迷迷糊糊把实现了要求,就没有再深入研究. 最近,想在配置文件里实现一个复杂的配置,多 ...
- 图解WinCE6.0下的内核驱动和用户驱动
图解WinCE6.0下的内核驱动和用户驱动 在<WinCE驱动程序的分类>中曾提到,WinCE6.0的流驱动既可以加载到内核态也可以加载到用户态.下面通过一组图片简单说明一下这两种驱动的关 ...
- 一步一步教你在CentOS6.0下安装NS2(ns-allinone-2.34.tar.gz)模拟仿真工具
在CentOS6.0(内核版本2.6.32-71.el6.i686 )发行版中,基于2.6.32的内核协议栈部分做了适当调整,因此我们在选择ns2的安装版本时就不可以选择较老的版本,因为很多东西都编译 ...
最新文章
- 怎样做好敏捷项目管理?
- MapReduce实现Apriori算法
- crio电压采集 labview_NI cDAQ917采集温度方法
- 现代软件工程 作业 2 结对项目
- 信息学奥赛一本通(1181:整数奇偶排序)——快速排序
- ROS2官网安装教程补充
- jquery获取前一个月日期
- linux python指令大全,Linux常用指令
- 爱卡创誓记java饰品,《创誓记AIKA》芙兰精灵配上框架眼睛折服宅男宅女
- Android Ptrace Inject
- MPU6050读取实验
- 公摊面积用计算机怎么计算,公摊面积计算(公摊面积计算器)
- chrome浏览器关闭更新弹窗
- nagios的配置官方文档篇
- uniapp nvue运用map组件实现地图标注以及检索周边地址
- 递归陷入死循环的判断方法与解决措施(java代码)
- 关于多径效应,平坦衰落,频率选择性衰落以及瑞利衰落的理解
- 文本生成任务常见评估指标
- 【转载】人生如梦游戏间,RPG游戏开源开发讲座(JAVA篇)[3]——邯郸学步
- outlook邮件开发开发HTML,CSS标签及样式失效总结
热门文章
- libpcap-mmap分析(五)
- 小程序接收json_微信推出QQ小程序,但只能接收消息无法回复!网友:鸡肋
- python用一行代码编写一个回声程序_一行python代码实现树结构
- 为什么道理都懂,却还是一事无成
- Linux(CentOS 5)下安装Oracle10 客户端(转)
- 昆仑网(D×××)去中心化虚拟互联网基础功能图片式介绍,请全屏看。
- 使用StarWind为RAC设置存储
- 内置付费 inapp purchase and Error Domain=SKErrorDomain Code=0 “Cannot connect to iTunes Store”错误...
- ActionScript 3.0 Step By Step系列(一):工欲其善,先利其器(Flex Builder)
- md5sum算法 —— linux或Unix上,md5sum是用来计算和校验文件报文摘要的工具程序