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!";
	}
}

Lies, damned lies, and statistics

Goldman Sachs statistical model for predicting the outcome of the 2014 World Cup

To be clear, our model does not use any information on the quality of teams or individual players that is not reflected in a team’s track record. For example, if a key player who was responsible for a team’s recent successes is injured, this will have no bearing on our predictions. There is also no role for human judgment as the approach is purely statistical.