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

Man*_*ete 7 c# design-patterns memento fsm

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

我正在使用状态模式在C#中重构状态机.目前我的状态机包含5个状态,只能通过状态前进或后退,即从状态1开始,你需要进入状态2,3和4,最后到达状态5.在此输入图像描述

我能够继续前进

       mainclass.State = new NextSate();
Run Code Online (Sandbox Code Playgroud)

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

Moh*_*bed 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();
   }
}
Run Code Online (Sandbox Code Playgroud)

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

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();
    }
}
Run Code Online (Sandbox Code Playgroud)


Ste*_*ham 10

严格来说,如果您正在实现经典的GoF State模式,那么State子类本身负责了解和执行State转换.状态的持有者不负责管理转换,并且模式的大部分意图是将状态转换行为封装在State对象中,从而使客户端委托给它们.我引入了一个Factory,它确保每个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;
    }
}
Run Code Online (Sandbox Code Playgroud)