代码结构
详细代码
StateBase.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using wg.workflow.Interface;
namespace wg.workflow.Core
{
public class StateDefintion
{
public const string Start = "Start";
public const string End = "End";
}
public class StateBase : IState, IEquatable<IState>
{
public readonly string StateId;
public IAction EnterAction { get; set; }
public IAction ExitAction { get; set; }
private Dictionary<string, ITransition> _transitionDic;
public StateBase(string stateId)
{
StateId = stateId;
_transitionDic = new Dictionary<string, ITransition>();
}
public string GetStateId()
{
return StateId;
}
private ITransition FindTransition(string transitionId)
{
return _transitionDic.ContainsKey(transitionId) ? _transitionDic[transitionId] : null;
}
public IState GoNext(string transitionId, object args)
{
var transition = FindTransition(transitionId);
if (null == transition)
return null;
if (null != transition.Actions)
{
foreach (var action in transition.Actions)
{
action.Execute(args);
}
}
return transition.To;
}
public bool IsTransitionRegistered(string transitionId)
{
return FindTransition(transitionId) != null;
}
public IList<string> ListTransitions()
{
return _transitionDic.Keys.ToList();
}
public bool RegisterTransition(ITransition transition)
{
if (null == transition || _transitionDic.ContainsKey(transition.TransitionId))
return false;
_transitionDic.Add(transition.TransitionId, transition);
return true;
}
public void Enter(object args)
{
EnterAction?.Execute(args);
}
public void Exit(object args)
{
ExitAction?.Execute(args);
}
public bool Equals(IState other)
{
return null != other && other.GetHashCode() == this.GetHashCode();
}
public override int GetHashCode()
{
return null != StateId ? StateId.GetHashCode() : 0;
}
}
}
StateMachineBase.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using wg.workflow.Interface;
namespace wg.workflow.Core
{
public class StateMachineBase : IStateMachine
{
public IState CurrentState { get; set; }
public HashSet<IState> _states;
public StateMachineBase()
{
_states = new HashSet<IState>();
}
public bool Transit(string transitionId, object args)
{
var newState = CurrentState.GoNext(transitionId, args);
if (null != newState)
{
CurrentState = newState;
return true;
}
return false;
}
public void RegisterState(IState state, bool isStart = false, bool isEnd = false)
{
if (null == state || _states.Contains(state))
return;
_states.Add(state);
if (isStart)
CurrentState = state;
}
}
}
TestAction.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using wg.workflow.Interface;
namespace wg.workflow.Core
{
public class TestAction : IAction
{
public TestAction(string actionName)
{
_actionName = actionName;
}
private string _actionName;
public bool CanExecute(object args)
{
return true;
}
public void Execute(object args)
{
Console.WriteLine("Action: {0}", _actionName);
}
}
}
TransitionBase.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using wg.workflow.Interface;
namespace wg.workflow.Core
{
public class TransitionBase : ITransition
{
public string TransitionId { get; }
public IState From { get; }
public IState To { get; }
public IList<IAction> Actions { get; }
public TransitionBase(string transitionId, IState from, IState to, IList<IAction> actions = null)
{
TransitionId = transitionId;
From = from;
To = to;
Actions = actions;
}
}
}
WorkflowBase.cs
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using wg.workflow.Interface;
namespace wg.workflow.Core
{
class WorkflowBase : IWorkflow
{
public event ProcedureChangedEventHandler ProcedureChanged;
private IStateMachine _stateM;
private BlockingCollection<KeyValuePair<string, object>> _requestQueue;
private Thread _requestHandleThread;
public IState CurrentState => _stateM.CurrentState;
public WorkflowBase(IStateMachine stateM)
{
_stateM = stateM;
_requestQueue = new BlockingCollection<KeyValuePair<string, object>>();
_requestHandleThread = new Thread(RequestHandler);
_requestHandleThread.IsBackground = true;
_requestHandleThread.Start();
}
private void RequestHandler()
{
foreach (var request in _requestQueue.GetConsumingEnumerable())
{
var preStateId = CurrentState.GetStateId();
if (_stateM.Transit(request.Key, request.Value))
{
ProcedureChanged?.Invoke(preStateId, CurrentState.GetStateId());
}
}
}
public bool GoNext(string transitionId, object context)
{
_requestQueue.Add(new KeyValuePair<string, object>(transitionId, context));
return true;
}
}
}
IAction.cs
namespace wg.workflow.Interface
{
public interface IAction
{
bool CanExecute(object args);
void Execute(object args);
}
}
IState.cs
using System.Collections.Generic;
namespace wg.workflow.Interface
{
public interface IState
{
string GetStateId();
bool RegisterTransition(ITransition transition);
IList<string> ListTransitions();
bool IsTransitionRegistered(string transitionId);
IAction EnterAction { get; }
IAction ExitAction { get; }
void Enter(object args);
void Exit(object args);
IState GoNext(string transitionId, object args);
}
}
IStateMachine.cs
using System.Collections.Generic;
namespace wg.workflow.Interface
{
public interface IStateMachine
{
IState CurrentState { get; }
void RegisterState(IState state, bool isStart = false, bool isEnd = false);
bool Transit(string transitionId, object args);
}
}
ITransition.cs
using System.Collections.Generic;
namespace wg.workflow.Interface
{
public interface ITransition
{
string TransitionId { get; }
IState From { get; }
IState To { get; }
IList<IAction> Actions { get; }
}
}
IWorkflow.cs
using System;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace wg.workflow.Interface
{
public delegate void ProcedureChangedEventHandler(string preState, string currentState);
public interface IWorkflow
{
IState CurrentState { get; }
bool GoNext(string transitionId, object context);
event ProcedureChangedEventHandler ProcedureChanged;
}
}
Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using wg.workflow.Core;
using wg.workflow.Interface;
namespace wg.workflow
{
class Program
{
static void Main(string[] args)
{
IStateMachine stateM = new StateMachineBase();
var stateStart = new StateBase("State_Start");
var stateA = new StateBase("State_A");
var stateB = new StateBase("State_B");
var stateC = new StateBase("State_C");
var stateEnd = new StateBase("State_End");
stateStart.RegisterTransition(new TransitionBase("S2A", stateStart, stateA));
stateA.RegisterTransition(new TransitionBase("A2B", stateA, stateB, new List<IAction>
{
new TestAction("A2BOne"),
new TestAction("A2BTwo")
}));
stateB.RegisterTransition(new TransitionBase("B2C", stateB, stateC, new List<IAction>
{
new TestAction("B2COne")
}));
stateC.RegisterTransition(new TransitionBase("C2E", stateC, stateEnd, new List<IAction>
{
new TestAction("C2EOne"),
new TestAction("C2EOne")
}));
stateM.RegisterState(stateStart, isStart: true);
stateM.RegisterState(stateA);
stateM.RegisterState(stateB);
stateM.RegisterState(stateC);
stateM.RegisterState(stateEnd, isEnd: true);
IWorkflow workflow = new WorkflowBase(stateM);
workflow.ProcedureChanged += Workflow_ProcedureChanged;
workflow.GoNext("S2A", null);
workflow.GoNext("A2B", null);
workflow.GoNext("B2C", null);
workflow.GoNext("C2E", null);
Console.Read();
}
private static void Workflow_ProcedureChanged(string preState, string currentState)
{
Console.WriteLine("StateChanged.. preState: {0} newState: {1}", preState, currentState);
}
}
}
对于状态机的实始化,可以定义xml配置反射生成,这里只给出简单的xml定义。
<?xml version="1.0" encoding="utf-8"?>
<StateMachine>
<States>
<State ID="Start">
<Transitions>
<Transition ID="S2A" To="A">
</Transition>
</Transitions>
</State>
<State ID="A" EnterAction="StartAAction">
<Transitions>
<Transition ID="A2B" To="B">
<Actions>
<Action Class="DoEmergencyAction"></Action>
</Actions>
</Transition>
<Transition ID="A2C" To="C"></Transition>
</Transitions>
</State>
<State ID="End">
</State>
</States>
</StateMachine>
运行结果