This is one of the variations of the behavioral design pattern. This is used for the reliability of the client. It allows for the restoration of the previous state of the object. We can say that it is the restoring point in the object's lifecycle. Conceptually, it is very much like we create restore points for operating systems and use them to restore the system if something breaks or the system crashes. The main factor is that we can regain the previous state without breaking the encapsulation, which means the client can use it and change the state to the previous state, and none of the internal structure of the code is exposed. All of us are aware of the undo function, and the memento design pattern is the same as undo because, at any particular point, the client or the user may desire to undo the action so that the memento design pattern can handle this type of case. If the state of an object is frequently changing, then using a memento design pattern is ideal, and the implementation details remain unrevealed. No fixed guidelines are available to implement this design pattern. It can be implemented in many different ways.
Components of the memento design pattern :
Originator: This is a particular state of an object that must be stored for future undo actions. If the client wants to regain the previous state, we can easily use the originator. This is an important component of the memento design pattern.
Memento: The originator's state must be maintained, which is done by memento. Memento takes the responsibility of managing the originator.
Caretaker: this is used to keep track of multiple mementos. as per the originator, we have to create multiple mementos to maintain the originator, and then we have to create a caretaker for the memento. It can be referred to as the manager of the application/software.
Where to use the memento design pattern :
- Suppose the object's state undergoes continuous or frequent change. In that case, we should use the memento design pattern so that the user can perform undo actions when needed, but the internal implementation remains unrevealed.
- If we want to continue our application/software from the last used state, we can use the memento design pattern to restore the previous state. Suppose you are working on a word file. Today you have written 200 words and then shut down the computer; the next day, you boot the computer and start working on that file again. So do you have to write from the beginning, or will you write from the last saved state where 200 words are already written? Of course, you will start from the last saved state, so this is the functionality of the memento design pattern. You can work from the last saved state if needed, and almost all applications have this functionality of saving the last activity.
- If direct access to the attributes of the object violates the encapsulation, we use a memento design pattern to solve the problem of breakage of encapsulation.
Problem statement :
Suppose you are working on software that is similar to a photo editor. Several functionalities should be added, such as filters, color correction, text, emojis, etc., so users may want to undo their actions at any moment. Over the years, the undoing feature has become very common. If your application does not have this feature, the user will easily move to any other application because picture editing is a daunting task without an undoing operation. So you decided to add an approach to add undo functionality. In the snapshot method, all the object's state is saved in any memory location before any action is done, which is done whenever the user changes something. After some time, when the user decides to revert the action, the existing snapshot is fetched from memory, and then the object regains its previous state. This is how the conventional method works.
There is a problem with the conventional method of saving or producing a snapshot. It would be best if you traversed through all the properties and attributes of an object and then saved it to memory. You have to do it repeatedly whenever a user makes any tiny change. There is one more problem: all the objects do not permit direct access. They contain some restrictions, so peeking inside the object is not always easy as it may contain some private data. Hence, using the conventional method is not always possible, undoing the actions. In the future, if you decide to make changes in any class, that also becomes tough as many classes are interrelated due to snapshot, so the changes cannot be implemented by working on some classes. You would have to change the basic structure as they have deployed dependencies. So now the question arises, how can we solve these problems?
Solution statement :
The above problem can be solved by using a memento design pattern. All the problems are occurring due to violations in the encapsulation. Some methods are peeking inside objects and taking more information than needed. The collected information must pass through some filters and some operations. While performing, they can invade the object's space, and the other methods cannot access it. That's why the breaking of encapsulation is happening.
The memento method uses an originator, a particular state of an object that needs to be stored for future undo action. If the client wants to regain the previous state, we can easily use the originator. This is an important component of the memento design pattern. So now we do not need to invade the object. Rather, it can create the snapshot by itself since full access to the state is given to the originator. The object's copy is stored in the memento itself. The originator's state must be maintained, and the memento does this. The most interesting factor is that whatever is contained and stored by the memento is only accessible to the particular object that produced it. An interface helps in the communication between them and maintains the metadata, and it is stored as a snapshot. The snapshot does not contain the original data state, and the complexity is reduced. The problem is also solved, and the functionality remains the same. This is how the memento design pattern helps the software and boosts its performance.
No other object can read the snapshot. Only the memento will be able to read it. It makes the state of the original object secure and safe. No other object will peek inside the original object's data and state. The memento object can also copy the object's private data, which means every attribute, no matter its price to the public, will be accessible to the memento, making this design pattern efficient and reliable.
The command design pattern can be used along with the memento design pattern to implement an undo feature. Sometimes we can use a prototype design pattern in the place of a memento design pattern because it is simple.
Advantages of the memento design pattern :
- Removing unwanted changes is an important part of any application. We can restore the object to its previous state easily. This can be done easily using a memento design pattern.
- The problem of violation of encapsulation is solved. Without violating the encapsulation, we are performing our necessary actions.
- The high cohesion is maintained by using a memento design pattern.
- The recovery technique is easy and simple. It can be implemented very easily and introduces almost no complexity.
- The originator's code is simplified with the help of the caretaker. The caretaker organizes the history of the original object's state.
Disadvantages of the memento design pattern :
- This method might overconsume the RAM if the client keeps creating mementos, which might slow down the speed of the process.
- The caretaker deletes the obsolete mementos while they keep track of the history of the object's lifecycle.
- Additional time taken by memento reduces the overall performance of the software.