State Pattern C # with previous states

I am new to implementing a state template in C #, you could provide some information on how you implement it.

I am reorganizing a state machine in C # using a state template. Currently, my state machine contains 5 states, and you can only move forward or backward in states, i.e. from state 1 you need to go to state 2, 3, and 4 in order to finally come to state 5. enter image description here

I can go ahead just by doing

mainclass.State = new NextSate(); 

which creates a new state every time you want to go forward, however, as soon as they are all created and / or you want to go back, I will need to go to the same states, not just the new one. How can i do this? Is there a better way to make this simple?

+7
source share
3 answers

Strictly speaking, if you implement the classic GoF state template, then state subclasses themselves are responsible for knowing and performing state transitions. The state owner is not responsible for transition management, and a significant part of the intent of the template is to encapsulate state transition behavior in State objects and, therefore, for the client to delegate to them. I introduced Factory, which ensures that there is only one instance of each State subclass, to ensure that the same instance is reused when moving back and forth through states.

 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; } } 
+10
source

Use the internal stack to save previous states:

 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(); } } 

if you want to keep the state back and forth, then create an extra stack:

 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(); } } 
+10
source

Do you have any state manager? If so, it would be possible to store copies of the state. By unleashing knowledge of the state transition from the states themselves, you allow the manager to make a decision about the transition. The manager checks the state requesting the transition: it determines that this state is "step 1", and returns (or creates) the state "state 2".

0
source

All Articles