Tim Van Wassenhove home

Now that i have presented a simple ControlStateMachine i can raise the bar a little. A statemachine that handles commands. Here is how a developer should be able to initialize this machine:

sut.WhenIn(States.Loading)
.On(Commands.Next)
.Do(() => Console.WriteLine("got next command while loading..."))
.Do(() => Console.WriteLine("doing it again..."))
.On(Commands.Previous)
.Do(() => Console.WriteLine("got previous command while loading..."));

sut.WhenIn(States.Ready)
.On(Commands.Previous)
.Do(() => Console.WriteLine("got previous command while ready..."));

So how should we define our methods to accomplish this initialization style? Let’s begin with identifying the methods we need.

Next thing to do is analyze in which sequence these methods can be called:

From -> To WhenIn On Do
WhenIn X
On X
Do X X

Ok, now that we have clarified the requirements a little we can start working on a solution. Let’s start with defining an interface for each of the methods:

interface IChooseState<tstate, TCommand> { Q1 WhenIn(TState state); }
interface IChooseCommand<tstate, TCommand> { Q2 On(TCommand command); }
interface IChooseAction<tstate, TCommand> { Q3 Do(Action action); }

From WhenIn we need to be able to call On. Thus Q1 = IChooseCommand<TState, TCommand>. Q2 is also easily solved because from On we only have to be able to call Do, thus Q2 = IChooseAction<TState, TCommand>.

From Do we should be able to call both On and Do. We can do that by defining another interface which has both methods:

interface IChooseCommandAndAction<tstate, TCommand> : IChooseCommand<tstate, TCommand>, IChooseAction<tstate, TCommand> { }

Now that we have found answers for Q1, Q2 and Q3 we can define the API for initializing our StateMachine as following:

IChooseCommand<tstate, TCommand> WhenIn(TState state);
IChooseAction<tstate, TCommand> On(TCommand command);
IChooseCommandAndAction<tstate, TCommand> Do(Action action);

Now tell me about your strategy for implementing a fluent interface!