I would like to use http://code.google.com/p/stateless in my code to separate the functionality from its dependencies. I didn't find any advanced examples of the usage, so this question is about stateless framework best practices.
I have following configuration (this is just example, has only one function state):
var stateMachine = new StateMachine(State.Stopped);
stateMachine.Configure(State.Stopped)
.Permit(Trigger.Failed, State.Error)
.Permit(Trigger.Succeed, State.GenerateMachineData);
stateMachine.Configure(State.GenerateMachineData)
.Permit(Trigger.Failed, State.Error)
.Permit(Trigger.Succeed, State.Finished);
public enum State
{
Stopped,
GenerateMachineData,
Finished,
Error
}
public enum Trigger
{
Succeed,
Failed
}
where to call the actual functionality then. I had following ideas but each of them has advantages and disadvantages:
1) Set the functionality as well as next fire in OnEntry():
stateMachine.Configure(State.GenerateMachineData)
.OnEntry(() => {
try {
Generate();
stateMachine.Fire(Trigger.Succeed);
} catch {
stateMachine.Fire(Trigger.Error);
}
})
.Permit(Trigger.Failed, State.Error)
.Permit(Trigger.Succeed, State.Finished);
so then if I just call
stateMachine.Fire(Trigger.Succeed);
it ends up either in State.Finished or State.Error
2) have statemachine and functionality separated like:
void DoTheStuff() {
switch (stateMachine.State)
{
State.Stopped:
stateMachine.Fire(State.Succeed);
break;
State.GenerateMachineData:
Generate();
stateMachine.Fire(State.Succeed);
break;
default:
throw new Exception();
}
}
void Main() { while (stateMachine.State != State.Succeed && stateMachine.State != State.Error) { DoTheStuff(); } }
3) some other solution?
I will be glad for any answer
Nicholas Blumhardt wrote good post about stateless framework.
I like BugTrackerExample which they have in source code.
So your machine would probably look like this:
class Generator
{
private readonly StateMachine state;
public Generator()
{
state = new StateMachine(State.Stopped);
// your definition of states ...
state.Configure(State.GenerateMachineData)
.OnEntry(() => { Generate(); })
.Permit(Trigger.Failed, State.Error)
.Permit(Trigger.Succeed, State.Finished);
// ...
}
public void Succeed()
{
state.Fire(Trigger.Succeed);
}
public void Fail()
{
state.Fire(Trigger.Fail);
}
public void Generate()
{
// ...
}
}
In this case tests shouldn't be problem.
If you need further separation you can use event, delegate or strategy pattern instead of Generate
method.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With