Basic State Machine setup using Stateless

2019-03-09 20:26发布

I have some fairly simple state needs (for now). I think I would like to model these using the Stateless api. (But I don't really know much about state machines, so I could be wrong.)

But I am getting caught up in the terminology (Specifically State and Trigger)

Here is an example: I have an order class. It is setup with several states. They are: New, Filled, Shipping, Completed, Cancelled.

A few simple state rules I would like is that these state transitions are allowed:

  • New (is the default)
  • New -> Filled
  • New -> Cancelled
  • Filled -> Shipping
  • Filled -> Cancelled
  • Filled -> Shipping
  • Shipping -> Complete

So where I am getting tripped up here is what is my "Trigger"?

Just in case a more specific example is needed, say I want a method like this:

public bool UpdateOrderStatus(int OrderId, OrderStatusEnum NewOrderStatus)

that will return true if the status updated successfully. How can setup and use Stateless to make this happen?

1条回答
爱情/是我丢掉的垃圾
2楼-- · 2019-03-09 20:44

The machine is in only one state at a time; the state it is in at any given time is called the current state. It can change from one state to another when initiated by a triggering event or condition, this is called a transition. from Finite-state machine on Wiki

I believe, the trigger is this triggering event.

Update:

Of course trigger name sometimes can be equal to some of state names.

New (initial state)
New -> Filled (trigger "Filled")
New -> Cancelled (trigger "Cancelled")
Filled -> Shipping (trigger "ToBeShipped")
Filled -> Cancelled (trigger "Cancelled")
Shipping -> Complete (trigger "Completed").

Update:

stateless is really nice framework! I've tried to implemented the functionality.

States:

public enum State
{
    New,
    Filled,
    Shipping,
    Cancelled,
    Completed
}

Triggers:

public enum Trigger
{
    Filled,
    Cancelled,
    ToBeShipped,
    Completed
}

Order class:

public class Order
{
    private readonly StateMachine<State, Trigger> _stateMachine;

    public Order()
    {
        _stateMachine = CreateStateMachine();
    }

    public bool TryUpdateOrderStatus(Trigger trigger)
    {
        if (!_stateMachine.CanFire(trigger))
            return false;

        _stateMachine.Fire(trigger);
        return true;
    }

    public State Status
    {
        get
        {
            return _stateMachine.State;
        }
    }

    private StateMachine<State, Trigger> CreateStateMachine()
    {
        StateMachine<State, Trigger> stateMachine = new StateMachine<State, Trigger>(State.New);
        stateMachine.Configure(State.New)
            .Permit(Trigger.Filled, State.Filled)
            .Permit(Trigger.Cancelled, State.Cancelled);

        stateMachine.Configure(State.Filled)
            .Permit(Trigger.ToBeShipped, State.Shipping)
            .Permit(Trigger.Cancelled, State.Cancelled);

        stateMachine.Configure(State.Shipping)
            .Permit(Trigger.Completed, State.Completed);

        stateMachine.OnUnhandledTrigger((state, trigger) =>
            {
                Console.WriteLine("Unhandled: '{0}' state, '{1}' trigger!");
            });
        return stateMachine;
    }
}

Tester for Order class:

Order order = new Order();
bool result = order.TryUpdateOrderStatus(Trigger.Completed);
Console.WriteLine("Attemp to complete order: {0}", result);
Console.WriteLine("Order status: {0}", order.Status);

result = order.TryUpdateOrderStatus(Trigger.ToBeShipped);
Console.WriteLine("Attemp to ship order: {0}", result);
Console.WriteLine("Order status: {0}", order.Status);

result = order.TryUpdateOrderStatus(Trigger.Cancelled);
Console.WriteLine("Attemp to cancel order: {0}", result);
Console.WriteLine("Order status: {0}", order.Status);
查看更多
登录 后发表回答