State pattern

The state pattern allows an object to alter its behavior when its internal state changes. The object will appear to change its class.

Featured image

Real-world example

StateExample

Client

static void Main(string[] args)
{
	var guessingMachine = new GuessingMachine(10);
	Console.WriteLine(guessingMachine.Message);
	guessingMachine.Start();

	while (!(guessingMachine.State is TerminateState))
	{				
		Console.WriteLine(guessingMachine.Message);
		guessingMachine.Play(Console.ReadLine());

	}
}

 

Context class

public class GuessingMachine	
{

	public GuessingMachine(int maxAttemptsNumber)
	{
		MaxAttemptsNumber = maxAttemptsNumber;
		State = new NewGameState(this);
	}


	public int MaxAttemptsNumber { private set; get; }

	public IState State { set; get; }

	internal string UserAnswer { set; get; }

	public string Message 
	{
		get { return State.Message; }
	}

	public void Play(string answer)
	{
		this.UserAnswer = answer;
		State.Handle(this);
	}

	public void Start()
	{
		State.Start(this);
	}

	public void Stop()
	{
		State.Stop(this);
	}
}

 

State interface

public interface IState
{
	string Message { set; get; }

	void Start(GuessingMachine context);

	void Stop(GuessingMachine context);

	void Handle(GuessingMachine context);
}

 

New game state class

public class NewGameState : IState
{
	public string Message { set; get; }

	public NewGameState(GuessingMachine context)
	{
		Message = String.Format("Pick a number between 1 and 10. You will have {0} turns. Good luck!", context.MaxAttemptsNumber);	
	}

	public void Handle(GuessingMachine context)
	{
		Message = String.Format("You should start a new game!");	
	}


	public void Start(GuessingMachine context)
	{
		var rand = new Random((int)DateTime.Now.Ticks & 0x0000FFFF);
		context.State = new GuessingState(context, rand.Next(1, 10));
	}

	public void Stop(GuessingMachine context)
	{
		context.State = new TerminateState(context);
	}
}

 

Guessing state class

public class GuessingState : IState
{
	public int Attempt { set; get; }
	public string Message { set; get; }

	private int NumberToGuess { set; get; }

	public GuessingState(GuessingMachine context, int numberToGuess)
	{
		Attempt = 1;
		NumberToGuess = numberToGuess;
		Message = String.Format("You have {0} attempts left", context.MaxAttemptsNumber);
	}

	public void Handle(GuessingMachine context)
	{
		int answer = int.Parse(context.UserAnswer);

		if (answer == NumberToGuess)
			context.State = new WinnerState();
		else if (Attempt >= context.MaxAttemptsNumber)
			context.State = new LoserState();
		else
		{
			Message = String.Format("You have {0} attempts left", context.MaxAttemptsNumber - Attempt);
			Attempt++;
		}
	}


	public void Start(GuessingMachine context)
	{
		context.State = new NewGameState(context);
		context.Start();
	}

	public void Stop(GuessingMachine context)
	{
		context.State = new TerminateState(context);
	}
}

 

Winner state class

class WinnerState : IState
{
	public string Message { set; get; }

	public WinnerState()
	{
		Message = "Good guess! You have won the game! Do you want to play a new game? (Y / N)";			
	}

	public void Handle(GuessingMachine context)
	{
		if (context.UserAnswer.ToUpperInvariant() == "Y")
			Start(context);
		else if (context.UserAnswer.ToUpperInvariant() == "N")
			Stop(context);
		Message = "Do you want to play a new game? (Y / N)";			
	}

	public void Start(GuessingMachine context)
	{
		context.State = new NewGameState(context);
		context.Start();
	}


	public void Stop(GuessingMachine context)
	{
		context.State = new TerminateState(context);
	}
}

 

Loser state class

public class LoserState : IState
{
	public string Message { set; get; }

	public LoserState()
	{
		Message = "You have lost the game!  Do you want to play a new game? (Y / N)";
	}

	public void Start(GuessingMachine context)
	{
		context.State = new NewGameState(context);
		context.Start();
	}

	public void Handle(GuessingMachine context)
	{
		if (context.UserAnswer.ToUpperInvariant() == "Y")
			Start(context);
		else if (context.UserAnswer.ToUpperInvariant() == "N")
			Stop(context);
		Message = "Do you want to play a new game? (Y / N)";			
	}


	public void Stop(GuessingMachine context)
	{
		context.State = new TerminateState(context);
	}
}

 

Terminate state class

public class TerminateState : IState
{
	public string Message
	{
		set;
		get;
	}

	public TerminateState(GuessingMachine context)
	{
		Message = "The game has been stopped!";
	}

	public void Start(GuessingMachine context)
	{
		context.State = new NewGameState(context);
		context.Start();
	}

	public void Stop(GuessingMachine context)
	{
		Message = "The game has been stopped!";
	}

	public void Handle(GuessingMachine context)
	{
		Message = "The game has been stopped!";
	}
}

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s