Memento Design Pattern explained with simple example

The Memento design pattern basically stores the various states of the system and provides the ability to restore the system in some previous state. This design pattern allows software to storing store various state which can be used for retracing or can be used to go back to some previous state in case something goes wrong. Also, auditing related procedures also can be done using this design pattern.

Before going ahead have a look at Design pattern simplified version.

Generic model class diagram of Memento design pattern is as shown in image.

Memento design pattern class diagram

This design pattern has following major component:

  • Originator – This class has states. For every state change it creates a memo or record its internal state which can be used to restore its state.
  • Memento – This class stores the states of Originator.
  • Caretaker – The caretaker class keeps track of Originator class and execute roll back or other actions.

Memento Design Pattern Code Example:

Let’s take an example of Banking system which is a classic example of Memento design pattern. In banking system, all the transactions for an account is stored and if needed rolled back in case of any incomplete or transaction failure.

#include <iostream>
#include <unistd.h>
#include <vector>
#include <memory>

using namespace std;

class Memento;

class BankAccount
{
	public:
		int balance;
		vector <shared_ptr <Memento>> statement;
		int current;

		BankAccount (int bal): balance (bal)
		{
			/* Storing initial state */
			current = 0;
			statement.push_back (make_shared <Memento> (balance));
		}

		shared_ptr<Memento> debit (int amount);
		shared_ptr<Memento> credit (int amount);
		shared_ptr<Memento> undo ();
		shared_ptr<Memento> redo ();
		void restore (const shared_ptr<Memento>& m);
};

class Memento
{
	public:
		int balance;

		Memento (int bal): balance (bal)
		{}

		friend class BankAccount;
};

shared_ptr<Memento> BankAccount::credit (int amount)
{
	balance = balance + amount;
	auto m = make_shared <Memento> (balance);
	/* saved the state in statement */
	statement.push_back (m);
	++current;
	return m;
}

shared_ptr<Memento> BankAccount::debit (int amount)
{
	balance = balance - amount;
	auto m = make_shared <Memento> (balance);
	/* saved the state in statement */
	statement.push_back (m);
	++current;
	return m;
}

shared_ptr<Memento> BankAccount::undo ()
{
	if (current)
	{
		/* undo only if some actions have already taken*/
		--current;
		auto m = statement[current];
		balance = m->balance;
		return m;
	}
	return {};
}

shared_ptr<Memento> BankAccount::redo ()
{
	/* check if there are some actions to do */
	if (current + 1 < statement.size ())
	{
		++current;
		auto m = statement[current];
		balance = m->balance;
		return m;
	}
	return {};
}

void BankAccount::restore (const shared_ptr<Memento>& m)
{
	if (m)
	{
		balance = m->balance;
		statement.push_back (m);
		current = statement.size () - 1;
	}
}

int main ()
{
	BankAccount savings (1000);
	cout <<"Account balance: "<< savings.balance << endl;
	savings.credit (3000);
	cout <<"Account balance: "<< savings.balance << endl;
	auto state = savings.debit (500);
	cout <<"Account balance: "<< savings.balance << endl;
	savings.undo ();
	cout <<"Account balance: "<< savings.balance << endl;
	savings.redo ();
	cout <<"Account balance: "<< savings.balance << endl;
	savings.credit (2000);
	cout <<"Account balance: "<< savings.balance << endl;
	savings.undo ();
	cout <<"Account balance: "<< savings.balance << endl;
	savings.restore (state);
	cout <<"Account balance: "<< savings.balance << endl;
	savings.redo (); /* No action */
	cout <<"Account balance: "<< savings.balance << endl;
}

Output of above example:

Account balance: 1000
Account balance: 4000
Account balance: 3500
Account balance: 4000
Account balance: 3500
Account balance: 5500
Account balance: 3500
Account balance: 3500
Account balance: 3500

Leave a Reply

Your email address will not be published. Required fields are marked *