20

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?

granadaCoder
  • 26,328
  • 10
  • 113
  • 146
Vaccano
  • 78,325
  • 149
  • 468
  • 850

1 Answers1

33

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);
  • @Vaccano - You vane't listed your triggers for us yet. For example, what action causes the New -> Filled transition? What action causes the New -> Cancelled transitions? I believe those would be your triggers. It looks like you don't tell the state machine which state transition to perform. You just define the triggers that cause state transitions, then fire triggers as they occur, and the state machine will do the state transitions. – mbeckish Feb 02 '12 at 18:20
  • @mbeckish - Thanks for your comment. It would appear that a state machine is not for me. I will have a WCF service call that fires this state transition. (ie `ShipOrders(List orderIds)`) I don't see how that can be made into an object. – Vaccano Feb 02 '12 at 18:24
  • @Serge - Thanks for your answer! I had another issue pull me away from this for a day or so. When I am able to get back to it I will look at the code (and accept if it works). Thanks again! – Vaccano Feb 03 '12 at 18:55
  • @Serge - Great answer, not sure why it hasn't been accepted, but helped me immensely...thanks! – swannee Mar 15 '13 at 02:18
  • @swannee, glad it was useful. – Sergey Vyacheslavovich Brunov Mar 15 '13 at 06:02