Learn Design Pattern - Memento Pattern

In my last article I spoke about the Mediator pattern; today we will have a glance at the Memento Patten.

Agenda

  • What is the Memento Pattern?
  • When to use the Memento Pattern?
  • Journey to the Memento Pattern.
  • What are the components of the Memento Pattern?
  • How to implement the pattern using C#? There is a code walkthrough here.
  • Class Diagram.

Previous Articles

  1. Design Patterns - Introduction
  2. Learn Design Pattern - Singleton Pattern
  3. Learn Design Pattern - Factory Method Pattern
  4. Learn Design Pattern - Abstract Factory Pattern
  5. Learn Design Pattern - Builder Pattern
  6. Learn Design Pattern - Prototype Pattern
  7. Learn Design Pattern - Adapter Pattern
  8. Learn Design Pattern - Composite Pattern
  9. Learn Design Pattern - Decorator Pattern
  10. Learn Design Pattern - Facade Pattern
  11. Learn Design Pattern - Flyweight Pattern
  12. Learn Design Pattern - Bridge Pattern
  13. Learn Design Pattern - Proxy Pattern
  14. Learn Design Pattern - Mediator Pattern

(For training related to .Net, OOP and design patterns contact me at [email protected].)

What is Memento Pattern?

The GOF says the "Memento Pattern lets us capture and externalize an object's internal state so that the object can be restored to this state later".

In short it adds the ability to UNDO to objects.

When to use Memento Pattern?

Can anyone tell me which is the best feature provided in Visual Studio?

Any guess? It's Undo and Redo. I don't think there is any developer who hasn't used this and praised Microsoft for the feature.

In OOP, we create an object of a class, assign values to properties (in other words we change the state of an object). Later we again change the state.

Now the point is: What if, it requires to rollback an object to a previous state?

Journey to Memento Pattern

Main Problem

Some provision for storing and retrieving the state of an object is needed.

Solution 1

Create 2 instances of the same object. One will be used as the backup object.

Problem 1

Solution 1 not accepted.

What if only part of the object needs to be restored? For example we have a Car object with 2 properties CurrentSpeed and TyreLife and it's possible to restore the Current speed but not Tyrelife.

Solution 2

Create one more class which will act as a Memento object that will contain a replica of the properties in the original class which can be restored.

For above example we will create a class called CarMemento with a single property called CurrentSpeed.

Problem 2

Solution 2

Seems fine and can be accepted but, where will be the backup (code that copies the value from an actual object to a Memento object) and restore logic (code that copies value from a Memento object to an actual object) will be?

Writing such logic in the final client code, makes the client code more complicated plus it's not possible to reuse the same backup and restore logic for other clients.

Solution 3

Backup and restore logic will be a part of the original class.

Here the Car class will have two member functions, SaveBackup and RestoreBackup.

These 2 functions answer WHAT to be stored and restored.

Problem 3

Solution 3 accepted.

We understad now. Now the original class will be responsible for its backup and restoration. It will create the Memento object which will be used by itself later for restoration purposes.

Wait a minute!! Where will the Memento object created by the original class (Car class) will be stored?

Solution 4

A separate class is created called Caretaker, which will store the Memento object created by the Original class.

Considering the example we are discussing about Car, the solution will be to create a class called CarCareTaker with the property of type CarMemento.

Question

Why is a separate class required for storing the Memeto Object, why we can't use the original class (Car class) for this purpose? (In other words why don't we create a property of type CarMemento in the Car class itself?)

Answer

Consider the client wants to store multiple backups, so that multiple undo is possible. Or it may possible, one asks for the restoration by a Time Period (restore my object to a state it was at 20/10/2012 2 PM).

Now the logic which decides how restoration and backup is to be done becomes more complex and it violates the SRP – Single Responsibility Principle.

Solution 4 accepted

Different components of Memento Pattern

Finally we conclude with the following components:

1. Originator – Class whose state needs to be restored. It will define methods that will specify what needs to be restored.
2. Memento – Class which contains replica of states defined in the Originator class. The Originator will be responsible for its creation.
3. CareTaker – Decides how restoration works.

Note: CareTaker is not required to always exist. Some people just skip that.

It depends on your problem statement, if you want to keep your "How backup and restore work" logic separate from "What is need to be backup and restore" logic, then probably use this class.

(For training related to .Net, OOP and design patterns contact me at [email protected])

Practical Demonstration

Output

Practical Demonstration.jpg

Code Walkthrough:

Step 1

Create Concrete Class Car

public class Car
{
          public int CurrentSpeed{get;set;}     
          public int TyreLife{          get;set;}
}

Step 2

Create Memento Class

internal class CarMomento
{
          public int CurrentSpeed{get;set;}
}

Step 3

Add SaveBackup and RestoreBackup methods to the Car Class to decide what needs backup and restore.

internal CarMomento SaveBackup()
{
          return new CarMomento()
          {
                   CurrentSpeed = this.CurrentSpeed
          };
}
internal void RestoreBackup(CarMomento objTaker)
{
          this.CurrentSpeed = objTaker.CurrentSpeed;
}

Step 4

Create Care Taker

public class CarCareTaker
{
          List<CarMomento> CarBackups = new List<CarMomento>();
          public void CreateBackup(Car objCustomer)
          {
                   CarBackups.Add(objCustomer.SaveBackup());
          }
          public void RestoreBackup(Car objCustomer,int Index)
          {
                   objCustomer.RestoreBackup(CarBackups[Index]);
                   for(int i = CarBackups.Count - 1; i >=Index; i--)
                   {
                             CarBackups.RemoveAt(i);
                   }
          }
}

Step 5

Client Code

Car objCar;
CarCareTaker objCareTaker = new CarCareTaker();
void btnBackup_Click(object sender, EventArgs e)
{
          Button objSender = sender as Button;
          objCareTaker.RestoreBackup(objCar, int.Parse(objSender.Tag.ToString()) - 1);
          this.FunPriSetControls();

private void BtnIncreaseSpeed_Click(object sender, EventArgs e)
{
          objCareTaker.CreateBackup(objCar);
          objCar.CurrentSpeed++;
          objCar.TyreLife -= 10;
          this.FunPriSetControls();
}

Class Diagram

class-diagram.jpg

Hope you enjoyed reading this article.

Comments and feedbacks are always welcome.

(For training related to .Net, OOP and design patterns contact me at [email protected])


Just Compile LLP
Just Compile is an IT based firm based out of Mumbai. Application Development, Staffing, Training