The Memento Design Pattern is about recording state. In a racing game there are sometimes the “ghosts” that is a shadow of your best run. These ghosts could have all their movements recorded by a memento and replayed during the game.

A memento has a simple implementation, it has a class to store the properties that will be recorded and a recorder that will store the values.

  1. public class Car
  2. {
  3. public int X { get; set; }
  4. public int Y { get; set; }
  5. // the class we want to record
  6. // will have a Memento property
  7. // returning a new memento every time
  8. // and setting the class properties
  9. // from the memento
  10. public CarMemento Memento
  11. {
  12. get { return new CarMemento(X, Y); }
  13. set
  14. {
  15. X = value.X;
  16. Y = value.Y;
  17. }
  18. }
  19. }
  20. // class with the properties that will be recorded
  21. public class CarMemento
  22. {
  23. public CarMemento(int x, int y)
  24. {
  25. X = x;
  26. Y = y;
  27. }
  28. public int X { get; set; }
  29. public int Y { get; set; }
  30. }

And we need a recorder to store a list of mementos.

  1. public class CarRecorder
  2. {
  3. private int currentIndex = -1;
  4. private IList<CarMemento> mementos = new List<CarMemento>();
  5. private Car car;
  6. public CarRecorder(Car car)
  7. {
  8. this.car = car;
  9. }
  10. public int NextIndex
  11. {
  12. get
  13. {
  14. if (mementos.Count == 0)
  15. return -1;
  16. int index = this.currentIndex + 1;
  17. return index >= mementos.Count
  18. ? mementos.Count - 1
  19. : index;
  20. }
  21. }
  22. public int PreviousIndex
  23. {
  24. get
  25. {
  26. if (mementos.Count == 0)
  27. return -1;
  28. return this.currentIndex - 1;
  29. }
  30. }
  31. public void Record()
  32. {
  33. mementos.Add(car.Memento);
  34. this.currentIndex++;
  35. }
  36. public void Forward()
  37. {
  38. if (NextIndex > -1)
  39. {
  40. car.Memento = mementos[NextIndex];
  41. this.currentIndex++;
  42. }
  43. }
  44. public void Rewind()
  45. {
  46. if (PreviousIndex > -1)
  47. {
  48. car.Memento = mementos[PreviousIndex];
  49. this.currentIndex--;
  50. }
  51. }
  52. }

Using it:

  1. var car = new Car();
  2. var recorder = new CarRecorder(car);
  3. car.X = 10;
  4. car.Y = 10;
  5. recorder.Record();
  6. car.X = 20;
  7. car.Y = 20;
  8. recorder.Record();
  9. car.X = 30;
  10. car.Y = 30;
  11. recorder.Record();

At this point we have 3 states saved on the recorder. We can iterate using the states by calling Forward and Rewind. Currently our car is at the following position:

  1. 30,30

But if we call the recorder method Rewind:

  1. recorder.Rewind();

Our car instance will now have X and Y set to 20.

  1. car.X // 20
  2. car.Y // 20
We can call forward and have the values set back to 30, 30.
  1. recorder.Forward();
  2. car.X // 30
  3. car.Y // 30
In a racing game the position of the car could be recorded every time and afterwards it can be replayed from the list of mementos allowing you to race against your own ghost.