DESIGN PATTERNS 2 — Memento Pattern

Memento pattern enables an object to restore to its previous state. It consists of three classes.

  • Originator is the one who has an internal state. It can save its current state to a Memento and restore its state from a Memento.
  • Memento is used to store the state of the Originator. It provides methods to be initialized from a state and to export the state.
  • Caretaker could be thought as an inventory of saved Mementos. It should provide managing services like adding Mementos to the inventory and popping them out.
TicTacToe Game

In this implementation, TicTacToe is the Originator, Snapshot is the Memento and History is the CareTaker.

class TicTacToe
{
	public TicTacToe()
	{
		this._state = Enumerable.Repeat((Mark?)null, 9).ToArray();
	}

	private Mark?[] _state;

	public void Place(Mark mark, int position)
	{
		this._state[position] = mark;
	}

	public void Print()
	{
		for (int i = 0; i < 3; i++)
		{
			for (int j = 0; j < 3; j++)
			{
				var mark = this._state[3 * i + j]?.ToString() ?? "_";
				Console.Write($"{mark}{tailChar}");
			}
		}
	}

	public Snapshot CreateSnapshot()
	{
		return new Snapshot(this._state);
	}

	public void RestoreSnapshot(Snapshot snapshot)
	{
		this._state = snapshot.GetState();
	}
}
class Snapshot
{
	public Snapshot(Mark?[] state)
	{
		state.CopyTo(this._state, 0);
	}

	private Mark?[] _state = new Mark?[9];

	public Mark?[] GetState()
	{
		return this._state;
	}
}
class History
{
	private List<Snapshot> _history = new List<Snapshot>();

	public void Push(Snapshot snapshot)
	{
		_history.Add(snapshot);
	}

	public Snapshot Pop()
	{
		var snapshot = _history[_history.Count - 1];
		_history.Remove(snapshot);
		return snapshot;
	}
}
enum Mark
{        
	X,
	O
}
class Program
{
	static void Main(string[] args)
	{
		var game = new TicTacToe();
		var history = new History();
		history.Push(game.CreateSnapshot());
		game.Place(Mark.X, 4);
		history.Push(game.CreateSnapshot());
		game.Place(Mark.O, 5);
		history.Push(game.CreateSnapshot());
		game.Place(Mark.X, 2);
		history.Push(game.CreateSnapshot());
		game.Place(Mark.O, 6);
		history.Push(game.CreateSnapshot());
		game.Place(Mark.X, 1);
		game.Print();
		game.RestoreSnapshot(history.Pop());
		game.Print();
		game.RestoreSnapshot(history.Pop());
		game.Print();
	}
}

Leave a comment