Momento pattern

Introduction:

Momento is a behavioral design pattern. It helps to store the objects internal state, and the object can return to its previous state later without violating the encapsulation. 

Example, 

Text editor provides the option to the user to save the current state and go back to the previous state when user press undo button. 

When to use, 

Need to restore an object back to its previous state (eg undo or rollback).

How does it work, 

There are three components. 1. Originator 2.Momento 3.Caretaker.

Originator:

  • Originator is the class for which we need to save its internal state and restore it back to the previous state when the user does undo operation. 
  • Momento pattern delegates creating the state snapshot to the actual owner of the state ie originator class.
  • Because some of the fields are private fields, only originator class has full access to save its private fields.
  • originator class has functionality to take snapshot of its internal state and restore it back.
  • But originator class doesn't contain the snapshots.

Momento:

  • This pattern suggests storing of object state in the special object called Momento.

Caretaker:

  • Caretaker role asks originator to take the snapshot and can ask the originator to restore its previous state.
  • Caretaker contains the snapshots in the form of momento objects.

The client  (caretaker class ) asks momento from the source object when it needs to checkpoint the source object state. The source object (Orginator class) initializes momento with its internal state.
The client is the caretakers of the momento, but only the source objects can store and restore the state from the momento. If the client subsequently wants to restore the source object state, it will handover the momento to source object for reinstatement.

How to use, 

  1. Identify the roles of “caretaker” and “originator”.
  2. Create a Memento class and declare the originator a friend.
  3. Caretaker knows when to "check point" the originator.
  4. Originator creates a Memento and copies its state to that Memento.
  5. Caretaker holds on to (but cannot peek into) the Memento.
  6. Caretaker knows when to "roll back" the originator.
  7. Originator reinstates itself using the saved state in the Memento.

Implementation:

Sourcecodehttps://github.com/krishnaKSA/design_patterns_cplusplus/blob/main/MomentoPattern/MomentoPattern.hpp

Class Diagram:


Momento Class:

  //Momento
    class Momento
    {
        //Orignator declared as friend class
        friend class Orginator;

        //state
        uint8_t state;

        //only orginator can access getstate    
        uint8_t getState()
        {
            return this->state;
        }

        public:
        Momento(uint8_t state)
        {
            this->state = state;
        }
    };

Originator class:

    //Class orginator
    class Orginator
    {
        private:
        //state
        uint8_t state;

        public:
        Orginator()
        {
            state = 0;
        }
        void doSomething()
        {
            state += 1;
        }

        //take snapshot of the state
        Momento* saveState()
        {
            printf("Orginator saved state %d \n",this->state);
            return new Momento(this->state);
        }

        //restore to previous state
        void undo(Momento* momento)
        {
            uint8_t currentState = this->state;
            this->state = momento->getState();
            printf("Orginator restore state current state %d  , restoring state %d \n",currentState, this->state);
        }

    };

Caretaker class:

    //Caretaker class
    class Caretaker
    {
        private:
        //Momento list
        vector<Momento*> momentoList;

        //orginator object
        Orginator* orginator;

        public:
        Caretaker(Orginator* org)
        {
            this->orginator = org;
        }
        //save the state
        void backup()
        {
            //get the momento from originator and save it to vector
            momentoList.push_back(orginator->saveState());
        }
       
        //Undo or rollback
        void restore()
        {
            if(momentoList.empty())
            {
                cout<<"Caretaker:: momento list is empty "<<endl;                
            }
            else
            {
                //send the momento to orginator
                orginator->undo(momentoList.back());
                //remove the last state from vector
                momentoList.pop_back();
            }            
        }
    };

Client code:

    void testClientCode()
    {
        Orginator* org = new Orginator();
        Caretaker* caretaker = new Caretaker(org);
        org->doSomething();
        caretaker->backup();
        org->doSomething();
        caretaker->backup();
        org->doSomething();
        caretaker->restore();
        caretaker->restore();
        caretaker->restore();
        caretaker->backup();
    }