Stateless范例及设计哲学

1、适用于明确状态流转的场景;

2、由事件推动状态切换;

3、描述 "规则",而非编写 "分支逻辑",流转规则集中收拢,可读性、可维护性大幅提升,复杂业务不会产生 "状态面条代码";

4、新增状态逻辑扩展很容易,代码较集中;

5、OnExit(Async)、OnEnter(Async)、OnEnterFrom(Async)钩子内可轻松完成业务逻辑;

cs 复制代码
        private Order _order;
        private void button1_Click(object sender, EventArgs e)
        {
            _order = new Order() { OrderMoney = 100};
            _order.Initialize();
        }

        private async void button2_Click(object sender, EventArgs e)
        {
            var state = await _order.PayOrder(59.5M);
            if (state == OrderStatus.Paid) 
            {
                button2.Enabled = false;
            }
        }

        private async void button3_Click(object sender, EventArgs e)
        {
            await _order.Send();
        }

        private async void button4_Click(object sender, EventArgs e)
        {
            await _order.Finish();
        }
cs 复制代码
using Microsoft.SqlServer.Server;
using Stateless;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace WindowsFormsApp_Stateless
{
    public class Order
    {
        private StateMachine<OrderStatus, OrderEvent> _stateMachine = new StateMachine<OrderStatus, OrderEvent>(OrderStatus.Created);

        public void Initialize()
        {
            _stateMachine.Configure(OrderStatus.Created)
                .OnExitAsync(async (evt) => {
                    Debug.WriteLine($"订单从{evt.Source}状态跳转到{evt.Destination}状态 Event={evt.Trigger}");
                })
                .Permit(OrderEvent.Pay, OrderStatus.Paid)
                .Ignore(OrderEvent.Send)
                .Ignore(OrderEvent.Finish);
            _stateMachine.Configure(OrderStatus.Paid)
                //.OnExit((evt) => {
                //    Debug.WriteLine($"订单从{evt.Source}状态跳转到{evt.Destination}状态 Event={evt.Trigger}");
                //})
                .OnExitAsync(async (evt) =>
                {
                    Debug.WriteLine($"{evt.Source} {evt.Trigger} {_stateMachine.State}  订单已支付,开始生成发货单");
                    //todo 订单状态切换到Paid,可以执行必要的业务操作,如生成发货单、锁定库存、发送支付通知等
                })
                .Permit(OrderEvent.Send, OrderStatus.Shipped)
                //.OnExit((evt) => {
                //    Debug.WriteLine($"订单从{evt.Source}状态跳转到{evt.Destination}状态 Event={evt.Trigger}");
                //})
                .Ignore(OrderEvent.Finish);
            _stateMachine.Configure(OrderStatus.Shipped)
                .OnEntryAsync(async (evt) =>
                {
                    Debug.WriteLine($"{evt.Source} {evt.Trigger} {_stateMachine.State}  订单已发货");
                    //todo 订单状态切换到Shipped,可以执行必要的业务操作,如...等
                })
                .Permit(OrderEvent.Finish, OrderStatus.Completed);
            _stateMachine.Configure(OrderStatus.Completed)
                .OnEntryAsync(async (evt) =>
                {
                    Debug.WriteLine($"{evt.Source} {evt.Trigger} {_stateMachine.State}  订单已完成");
                    //todo 订单状态切换到Shipped,可以执行必要的业务操作,如...等
                });
        }

        public OrderStatus GetOrderStatus() => _stateMachine.State;

        public decimal OrderMoney { get; set; }

        public List<(DateTime time, string log, decimal payMoney)> PayLog = new List<(DateTime time, string log, decimal payMoney)>();

        public async Task<OrderStatus> PayOrder(decimal money)
        {
            var payMoney = Math.Min(OrderMoney, money);
            PayLog.Add((DateTime.Now, $"第{PayLog.Count}次支付{payMoney}元,剩余{OrderMoney - payMoney}元", payMoney));
            OrderMoney -= payMoney;
            if (OrderMoney == 0)
                await _stateMachine.FireAsync(OrderEvent.Pay);
            return _stateMachine.State;
        }

        public async Task Send()
        {
            await _stateMachine.FireAsync(OrderEvent.Send);
        }

        public async Task Finish()
        {
            await _stateMachine?.FireAsync(OrderEvent.Finish);
        }
    }

    public enum OrderStatus
    {
        Created = 0,
        Paid,
        Shipped,
        Completed
    }

    public enum OrderEvent
    {
        Pay,
        Send,
        Finish
    }
}