Back to: Java Design Patterns
Memento Design Pattern in Java
In this article, I am going to discuss the Memento Design Pattern in Java with Examples. Please read our previous article where we discussed the Iterator Design Pattern in Java with Examples. The Memento Design Pattern falls under the category of Behavioral Design Pattern. In this article, we will explore the fundamental principles, advantages, and potential disadvantages of the Memento design pattern, emphasizing its significance in managing object states and supporting undo/redo functionality.
What is Memento Design Pattern?
In software development, there are often situations where objects need to be able to save and restore their internal states. The Memento design pattern provides a solution by separating the state management from the object itself. By encapsulating the object’s state in a separate memento object, the pattern enables the object to save and restore its state without exposing its internal details.
The Memento design pattern is a behavioral pattern that allows objects to capture and restore their internal states. It consists of three primary components: the originator, the memento, and the caretaker. The originator represents the object whose state needs to be saved or restored. A memento is a separate object that encapsulates the state of the originator at a particular point in time. The caretaker is responsible for managing the mementos and facilitating the saving and restoring of states. The originator creates a memento to capture its current state, and the caretaker stores the memento. Later, when needed, the originator can restore its state by retrieving the appropriate memento from the caretaker.
Example to Understand Memento Design Pattern:
Please have a look at the following image. As shown in the below image, on the left-hand side, we have an employee with Id =101, Name =John, Salary = 2Lakhs, Designation = Software Engineer, Address = London, and many more attributes. Later, we change some of the properties i.e. Salary to 3Lakhs, Designation to Senior Software Engineer, like this we also change some other attributes of the employee which are shown on the right-hand side of the below image. That means we change the object state from State 1 to State 2.
After some time, we think that let’s undo or roll back the employee information to its previous state i.e. State 1. If this is your requirement, then you need to use the Memento Design Pattern and roll back the employee information to its previous state.
Implementing Memento Design Pattern in Java
A real-world example where the Memento design pattern can be applied is in an application that has multiple states. For example, the application needs to provide an undo/redo functionality that allows users to revert back to previous “states”.
The Memento pattern can be used to implement the undo/redo feature. When a user performs an action, a memento object is created to capture the state at that point in time. The memento object stores the necessary information to restore the application to that specific state.
The memento objects are then managed by a caretaker object, which keeps track of the mementos in a stack or list. When a user requests an undo operation, the caretaker retrieves the previous memento from the stack and restores the application to that state. Similarly, the caretaker can handle redo operations by retrieving the next memento from the stack and applying it to the document.
By using the Memento pattern, the text editor application provides a convenient way for users to undo or redo their actions. It allows for the restoration of previous document states, enabling users to revert back to an earlier version if they make a mistake or change their mind. The UML Diagram of this example is given below using Memento Design Pattern.
Step 1: Create a new directory to store all the class files of this project.
Step 2: Open VS Code and create a new project, called Memento.
Step 3: In the project, create a new file called Memento.java. Add the following code to the file:
public class Memento { private String state; public Memento(String state) {this.state = state;} public String getState() {return state;} }
This is the interface from which other concrete classes will extend.
Step 4: In the project, create a new file called Originator.java. Add the following code to the file:
public class Originator { private String state; public void setState(String state) {this.state = state;} public String getState() {return state;} public Memento saveStateToMemento() {return new Memento(state);} public void getStateFromMemento(Memento memento){state = memento.getState();} }
Step 5: In the project, create a new file called CareTaker.java. Add the following code to the file:
import java.util.ArrayList; import java.util.List; public class CareTaker { private List<Memento> mementoList = new ArrayList<Memento>(); public void add(Memento state) {mementoList.add(state);} public Memento get(int index) {return mementoList.get(index);} }
Step 6: In the project, create a new file called MementoPatternDemo.java. This class will contain the main() function. Add the following code to MementoPatternDemo.java:
public class MementoPatternDemo { public static void main(String[] args) { Originator originator = new Originator(); CareTaker careTaker = new CareTaker(); originator.setState("State #1"); careTaker.add(originator.saveStateToMemento()); originator.setState("State #2"); careTaker.add(originator.saveStateToMemento()); originator.setState("State #3"); System.out.println("Current State: " + originator.getState()); originator.getStateFromMemento(careTaker.get(0)); System.out.println("First saved State: " + originator.getState()); originator.getStateFromMemento(careTaker.get(1)); System.out.println("Second saved State: " + originator.getState()); } }
This main() function creates several states in mementos. It then retrieves them and prints the state
Step 11: Compile and execute the application. Ensure compilation is successful. Verify that the program works as expected.
Congratulations! You now know how to implement Memento Design Pattern.
UML Diagram of Memento Design Pattern:
Now, let us see the Memento Design Pattern UML Diagram Components with our Example so that you can easily understand the UML Diagram.
The classes can be described as follows:
- Memento: This is the memento object which will be used to store one state of the application.
- Originator: This class is the handler for the mementos. It is responsible for saving and retrieving the mementos.
- CareTaker: This is the class in which the mementos will be stored.
- DriverClass: This class contains the main() function and is responsible for the simulation of the program.
Advantages of Memento Design Pattern in Java
The advantages of using the Memento Design Pattern in Java are as follows:
- State Preservation and Restoration: The Memento pattern provides a convenient way to save and restore object states. It enables objects to capture their internal state without exposing it to other objects. This feature is particularly useful in scenarios where objects need to support undo/redo functionality or checkpointing. By storing mementos, objects can revert to their previous states, allowing for easy state management and recovery.
- Encapsulation and Information Hiding: The Memento pattern promotes encapsulation and information hiding by separating state management from the object itself. The object’s internal state is encapsulated within the memento object, which is only accessible to the object itself or the caretaker. This encapsulation enhances code clarity and maintainability, as it hides the implementation details of the object’s state and ensures that only the object has control over its state.
- Flexibility in Undo/Redo Operations: The Memento pattern provides flexibility in implementing undo/redo operations. By storing multiple mementos, objects can maintain a history of states, allowing for seamless undoing and redoing of actions. This flexibility is valuable in scenarios where users need to revert to previous states or traverse through a sequence of actions.
- Support for Transactional Behavior: The Memento pattern supports transactional behavior by allowing objects to save and restore states at different points during their lifecycle. Objects can create mementos before making changes and roll back to previous states if needed. This feature ensures data integrity and consistency by providing a mechanism to recover from errors or undesired changes.
- Reduced Coupling: The Memento pattern reduces coupling between objects by separating state management from the originator. Objects that rely on the originator do not need to be aware of their internal state or implementation details. They interact only with the originator’s public interface, enhancing modularity and reducing dependencies.
Disadvantages of Memento Design Pattern in Java
The disadvantages of using the Memento Design Pattern in Java are as follows:
- Increased Memory Usage: The Memento pattern can increase memory usage, particularly when objects need to store a large number of mementos. Each memento requires memory allocation to store the state of the originator, and maintaining a significant history of states can lead to memory overhead. Care should be taken to manage memory usage and consider trade-offs when dealing with resource-constrained environments.
- Performance Overhead: The Memento pattern may introduce performance overhead, especially when objects have complex state structures or when frequent state saving and restoration operations occur. The process of creating and restoring mementos involves copying or serialization, which can impact the overall performance of the system. It is important to assess the performance requirements of the application and optimize the implementation if necessary.
- Exposing Internal State: While the Memento pattern encapsulates the object’s state within the memento object, there is a potential risk of exposing sensitive or internal information. If the memento object is accessible to other objects or if its contents are not properly controlled, it may compromise the encapsulation and information-hiding principles. Care should be taken to ensure that only the originator or authorized objects have access to the memento objects.
- Managing Memento Lifecycle: The Memento pattern requires careful management of the memento objects and their lifecycle. The responsibility of creating, storing, and disposing of mementos falls on the caretaker or the originator. If not managed properly, it can lead to memory leaks, excessive storage usage, or inconsistencies in state restoration. Proper design and adherence to best practices are essential to ensure the correct and efficient management of mementos.
In the next article, I am going to discuss Mediator Design Pattern in Java with Examples. Here, in this article, I try to explain Memento Design Pattern in Java with Examples. I hope you understood the need for and use of the Memento Design Pattern in Java.