自定义Workflow的代码实现

代码结构
这里写图片描述

详细代码

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>

运行结果
这里写图片描述

猜你喜欢

转载自blog.csdn.net/wujingang/article/details/80692778