實現狀態機有多種模式,其中最靈活而強大的方式是通過遷移表來實現,該方式的缺點之一是需要編寫大量小塊代碼去支持遷移表。而在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));
}
}
}
posted on 2008-11-25 11:55
墻頭草 閱讀(1087)
評論(0) 編輯 收藏