C++ Memento Pattern Example

In this article, we will learn how to use and implement the Memento Pattern in C++ with an example.

Memento is a behavioral design pattern that lets you save and restore the previous state of an object without revealing the details of its implementation.

C++ Memento Pattern Example

The below diagram shows the generic structure of the Memento Pattern:
Let's refer to the above structure to create an example to demonstrates the usage of the Memento Pattern.
#include <iostream>
#include <vector>

/*
 * Memento
 * stores internal state of the Originator object and protects
 * against access by objects other than the originator
 */
class Memento
{
private:
    // accessible only to Originator
    friend class Originator;

    Memento( const int s ) : state( s ) {}

    void setState( const int s )
    {
        state = s;
    }

    int getState()
    {
        return state;
    }
    // ...

private:
    int state;
    // ...
};

/*
 * Originator
 * creates a memento containing a snapshot of its current internal
 * state and uses the memento to restore its internal state
 */
class Originator
{
public:
    // implemented only for printing purpose
    void setState( const int s )
    {
        std::cout << "Set state to " << s << "." << std::endl;
        state = s;
    }

    // implemented only for printing purpose
    int getState()
    {
        return state;
    }

    void setMemento( Memento* const m )
    {
        state = m->getState();
    }

    Memento *createMemento()
    {
        return new Memento( state );
    }

private:
    int state;
};

/*
 * CareTaker
 * is responsible for the memento's safe keeping
 */
class CareTaker
{
public:
    CareTaker( Originator* const o ) : originator( o ) {}

    ~CareTaker()
    {
        for ( unsigned int i = 0; i < history.size(); i++ )
        {
            delete history.at( i );
        }
        history.clear();
    }

    void save()
    {
        std::cout << "Save state." << std::endl;
        history.push_back( originator->createMemento() );
    }

    void undo()
    {
        if ( history.empty() )
        {
            std::cout << "Unable to undo state." << std::endl;
            return;
        }

        Memento *m = history.back();
        originator->setMemento( m );
        std::cout << "Undo state." << std::endl;

        history.pop_back();
        delete m;
    }

private:
    Originator *originator;
    std::vector<Memento*> history;
};


int main()
{
    Originator *originator = new Originator();
    CareTaker *caretaker = new CareTaker( originator );

    originator->setState( 1 );
    caretaker->save();

    originator->setState( 2 );
    caretaker->save();

    originator->setState( 3 );
    caretaker->undo();

    std::cout << "Actual state is " << originator->getState() << "." << std::endl;

    delete originator;
    delete caretaker;

    return 0;
}

Output

Set state to 1.
Save state.
Set state to 2.
Save state.
Set state to 3.
Undo state.
Actual state is 2.

When to use?

  • a snapshot of an object's state must be saved so that it can be restored to that state later
  • a direct interface to obtaining the state would expose implementation details and break the object's encapsulation

Comments