Initiel kode:
public abstract class StepBase
{
protected Dictionary _transitions = new Dictionary();
internal virtual void Cleanup()
{
}
internal virtual void Initialize()
{
}
internal void Attach(Enum trigger, StepBase target)
{
_transitions.Add(trigger, new Transition(this, target));
}
public TransitionResult Dispatch(Enum trigger)
{
if (_transitions.ContainsKey(trigger))
return new TransitionResult(_transitions[trigger].Target);
return TransitionResult.NoTransition;
}
}
public class Sequence
{
private StepBase _current;
public StepBase Current
{
get { return _current; }
}
protected virtual void SetCurrent(StepBase step)
{
if (step == null)
throw new ArgumentNullException("step");
if (_current != step)
{
try
{
if (_current != null)
_current.Cleanup();
step.Initialize();
_current = step;
}
catch (Exception ex)
{
_current = new Error(ex);
OnStepError(EventArgs.Empty);
}
OnStepChange(EventArgs.Empty);
}
}
#region Events
private void OnStepChange(EventArgs eventArgs)
{
if (StepChange != null)
StepChange(this, eventArgs);
}
public event EventHandler StepError;
private void OnStepError(EventArgs eventArgs)
{
if (StepError != null)
StepError(this, eventArgs);
}
public event EventHandler StepChange;
#endregion
public class Error : StepBase
{
public Error(Exception exception)
{
this.LastError = exception;
}
public Exception LastError { get; private set; }
}
}
Efter lidt kritik på bloggen, og en realicering af, at koden virkelig "stank" kom den til at se sådan ud:
Største ændring er at jeg har fjernet de to virtuelle metoder: Initialize og Cleanup – de er erstattet af delegates, så klassen kan kalde evnetuel kode. Desuden er SetCurrent i Sequence erstattet med Raise(Enum trigger), og ansvaret for at kalde Enter (tidligere: Initialize()) og Exit() (tidligere Cleanup()), er flyttet ud i Step-klassen (tidligere StepBase).
public class Step
{
protected Dictionary _transitions = new Dictionary();
public string Name { get; protected set; }
public Step Raise(Enum trigger)
{
if (_transitions.ContainsKey(trigger))
{
try
{
OnExit(EventArgs.Empty); // Ryd op
var target = _transitions[trigger].Target;
target.OnEnter(EventArgs.Empty); // Gør klar
return target;
}
catch (Exception ex)
{
return new ErrorStep(ex);
}
}
return this;
}
protected void Attach(Enum trigger, Step target)
{
_transitions.Add(trigger, new Transition(this, target));
}
protected Action Enter;
protected void OnEnter(EventArgs args)
{
if (Enter != null)
Enter();
}
protected Action Exit;
protected void OnExit(EventArgs args)
{
if (Exit != null)
Exit();
}
}
public class Sequence
{
protected int _default;
protected Step _current;
protected Step[] _steps = new Step[0];
public Step Current
{
get { return _current; }
}
public void Do(Enum trigger)
{
if (_current != null)
{
var target = _current.Raise(trigger);
if (_current != target)
{
OnStepChange(EventArgs.Empty);
_current = target;
}
if (target.GetType() == typeof(ErrorStep))
OnError(new ErrorEventArgs((target as ErrorStep).LastError));
}
}
#region Events
public event EventHandler StepChange;
private void OnStepChange(EventArgs eventArgs)
{
if (StepChange != null)
StepChange(this, eventArgs);
}
public event EventHandler Error;
private void OnError(ErrorEventArgs eventArgs)
{
if (Error != null)
Error(this, eventArgs);
}
#endregion
}