具有先前状态的状态模式C#

时间:2011-10-24 10:10:30

标签: c# design-patterns fsm memento

我是C#中状态模式实现的新手,你能否提供一些关于如何实现它的信息。

我正在使用状态模式在C#中重构状态机。目前我的状态机包含5个状态,只能通过状态前进或后退,即。从状态1开始,您需要进入状态2,3和4,最终到达状态5. enter image description here

我能够继续前进

       mainclass.State = new NextSate();

每次你想要前进时都会创建一个新状态,但是,一旦创建了所有状态和/或你想要后退,我就需要进入相同的状态,而不仅仅是新状态。我怎样才能做到这一点?有没有更好的方法来做到这一点?

3 个答案:

答案 0 :(得分:10)

使用内部堆栈来维护以前的状态:

public class MyClass
{
  private Stack<State> _states;

  private State _currentState;

  public void GoToNextState()
  {
    // If Not last state then
    _states.Push(_currentState);
    _currentState = new NextState();
  }

  public void GoToPrevState()
  {
    // if not the first state
    _currentState = _states.Pop();
   }
}

如果你想保持前进和后退状态,那么创建额外的堆栈:

public class MyClass
{
    private readonly Stack<State> _nextStates = new Stack<State>();
    private readonly Stack<State> _prevStates = new Stack<State>();

    private State _currentState = new SampleState1();

    public State CurrentState { get { return _currentState; } }

    public void GoToNextState()
    {
        if (_currentState.NextState == null)
            return;

        _prevStates.Push(_currentState);

        _currentState = _nextStates.Count > 0 ? _nextStates.Pop() : _currentState.NextState;
    }

    public void GoToPrevState()
    {
        // if not the first state

        _nextStates.Push(_currentState);
        _currentState = _prevStates.Pop();
    }
}

答案 1 :(得分:10)

严格地说,如果你正在实现经典的GoF状态模式,那么State子类本身负责了解和执行状态转换。状态的持有者不负责管理转换,并且模式的大部分意图是将状态转换行为封装在State对象中,从而使客户端委托给它们。我引入了一个工厂,它确保每个State子类只有一个实例,以确保在状态中来回移动时重用相同的实例。

public abstract class State
{
   protected StateFactory _factory;
   protected IStateUser _context;

   public State(StateFactory factory, IStateUser context)
   {
      _factory = factory;
      _context = context;
   }

   protected void TransitionTo<T>(Func<T> creator) where T : State
   {
       State state = _factory.GetOrCreate<T>(creator);
       _context.CurrentState = state;
   }

   public abstract void MoveNext();
   public abstract void MovePrevious();
}

public class State1 : State
{
   public State1(StateFactory factory, IStateUser context)
            : base(factory, context)
   {
   }

   public override void MoveNext()
   {
      TransitionTo<State2>(() => new State2(_factory, _context));
   }

   public override void MovePrevious()
   {
      throw new InvalidOperationException();
   }
}

public class State2 : State
{
   public State2(StateFactory factory, IStateUser context)
            : base(factory, context)
   {
   }

   public override void MoveNext()
   {
      TransitionTo<State3>(() => new State3(_factory, _context)); //State 3 is omitted for brevity
   }

   public override void MovePrevious()
   {
      TransitionTo<State1>(() => new State1(_factory, _context));
   }
}

public interface IStateUser
{
   State CurrentState { get; set; }
}

public class Client : IStateUser
{

   public Client()
   {
      var factory = new StateFactory();
      var first = new State1(factory, this);
      CurrentState = factory.GetOrCreate<State1>(() => first);
   }

   public void MethodThatCausesTransitionToNextState()
   {
      CurrentState.MoveNext();
   }

   public void MethodThatCausesTransitionToPreviousState()
   {
      CurrentState.MovePrevious();
   }

   public State CurrentState
   {
      get;
      set;
   }
}

public class StateFactory
{
    private Dictionary<string, State> _states = new Dictionary<string, State>();

    public State GetOrCreate<T>(Func<T> creator) where T : State
    {
        string typeName = typeof(T).FullName;

        if (_states.ContainsKey(typeName))
            return _states[typeName];

        T state = creator();
        _states.Add(typeName, state);

        return state;
    }
}

答案 2 :(得分:0)

你有某种形式的州长吗?如果是这样,那个可以保存状态实例。通过将状态转换知识与状态本身分离,您可以让经理决定转换。经理将检查请求转换的状态:它确定它是&#34;步骤1&#34;状态,并返回(或创建)&#34;状态2&#34;状态。