Memento Design Pattern in Modern C++ is a very straight forward Behavioural Design Pattern. The motivation behind using the Memento Design Pattern is to keep some sort of token which then allows you to restore an object to a particular state. This is particularly useful if you have a system with medieval components i.e. an object or indeed a set of objects goes through a set of changes.

By the way, If you haven’t check out my other articles on Behavioural Design Patterns, then here is the list:

  1. Chain of responsibility
  2. Command
  3. Interpreter
  4. Iterator
  5. Mediator
  6. Memento
  7. Observer
  8. State
  9. Strategy
  10. Template Method
  11. Visitor

The code snippets you see throughout this series of articles are simplified not sophisticated. So you often see me not using keywords like override, final, public(while inheritance) just to make code compact & consumable(most of the time) in single standard screen size. I also prefer struct instead of class just to save line by not writing “public:” sometimes and also miss virtual destructor, constructor, copy constructor, prefix std::, deleting dynamic memory, intentionally. I also consider myself a pragmatic person who wants to convey an idea in the simplest way possible rather than the standard way or using Jargons.

Note:

  • If you stumbled here directly, then I would suggest you go through What is design pattern? first, even if it is trivial. I believe it will encourage you to explore more on this topic.
  • All of this code you encounter in this series of articles are compiled using C++20(though I have used Modern C++ features up to C++17 in most cases). So if you don’t have access to the latest compiler you can use https://wandbox.org/ which has preinstalled boost library as well.

Intent

To store and restore the state of the component/object.

  • In keep changing & well-designed OOPs software systems, the usual problem you may face while implementing rollback functionality is encapsulation. Because the object’s representation (data structure) is hidden. And can’t access from outside the object directly without using setter & getter.
  • Memento Design Pattern is the right way to address this problem. Memento is a kind of immutable object. It captures & externalizes an object’s internal state at given a particular time without violating encapsulation. So that the object can restore to that state on later point of time.

Memento Design Pattern Example in C++

  • With continuing our previous example of the bank account from Command Design Pattern where we were recording every change as a command & made facility to undo that command using member function.
  • Here in Memento Design Pattern, we simply save the snapshot of the system/component at a particular point of time. And allow the user to roll back the system to that snapshot.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
class BankAccount {
    int32_t         m_balance{0};
    uint32_t        m_current{0};

    struct Memento {
        int32_t m_balance;
        Memento(int32_t b): m_balance(b) {}
    };

    vector<shared_ptr<const Memento>>   m_changes;
public:
    BankAccount(const int32_t b): m_balance(b) {
        m_changes.emplace_back(make_shared<const Memento>(m_balance));
    }

    const shared_ptr<const Memento> deposit(int32_t amount) {
        m_balance += amount;
        m_changes.emplace_back(make_shared<const Memento>(m_balance));
        return m_changes[m_current++];
    }

    void restore(const shared_ptr<const Memento>& m) {
        if (m) {
            m_balance = m->m_balance;
            m_changes.push_back(m);
            m_current = m_changes.size() - 1;
        }
    }

    const shared_ptr<const Memento> undo() {
        if (m_current > 0) {
            m_balance = m_changes[--m_current]->m_balance;
            return m_changes[m_current];
        }
        return {};
    }

    const shared_ptr<const Memento> redo() {
        if ((m_current + 1) < m_changes.size()) {
            m_balance = m_changes[++m_current]->m_balance;
            return m_changes[m_current];
        }
        return {};
    }

    friend ostream& operator<<(ostream & os, const BankAccount & ac) {
        return os << "balance: " << ac.m_balance;
    }
};

int main() {
    BankAccount ba{100};
    ba.deposit(50);
    ba.deposit(25);
    cout << ba << "\n"; // 175

    ba.undo();
    cout << "Undo 1: " << ba << "\n";
    ba.undo();
    cout << "Undo 2: " << ba << "\n";
    ba.redo();
    cout << "Redo 2: " << ba << "\n";

    return EXIT_SUCCESS;
}
/*  
balance: 175
Undo 1: balance: 150
Undo 2: balance: 100
Redo 2: balance: 150
*/
  • So as you can see the state of the system is sufficiently small in terms of the memory footprint to actually record every single change and as a result not only do you get the user to be able to restore the system to any particular state just by using the memento.
  • But you also have this ability to walk forwards and backwards in terms of the overall timeline. You let the user kind of undo and redo depending on their needs.
  • So this is the proper way by which you can implement memento to jump back from one state to another. Undo mechanism is slightly different from we have seen earlier in the Command Design Pattern.

Benefits of Memento Design Pattern

  • Because what we’re doing here is Undo-ing at a discrete point of time unlike a line of changes we looked at the Command Design Pattern. By using memento, you can go backwards and forwards or you can go to discrete points of time that you’ve saved by saving a memento of that point in time & restore it.
  • A memento is very useful in almost all applications which must restart from their last known working state or draft. An example of this can be an IDE which restarts from changes user-made before closing the IDE.
  • Memento Design Pattern maintains high cohesion.

Summary by FAQs

Difference between Command & Memento Design Pattern?

  • In Command Design Pattern, the token represents a request; in Memento, it represents the internal state of an object at a particular time.
  • Polymorphism is important to Command Design Pattern, but not to Memento because its interface is so narrow that a memento can only be passed as a value.

Difference between State & Memento Design Pattern?

  • State Design Pattern is used to dictates the previous, current or future behaviour of the system.
  • While Memento Design Pattern is typically used to store only the historical state of an object which also does not have any direct relation to behaviour.