Memento mode - the implementation of the undo function

1 Introduction

1.1. Overview

The Memento mode provides a mechanism for implementing state recovery, allowing users to easily return to a specific historical step. When the new state is invalid or has problems, the temporarily stored memo can be used to restore the state. At present, many software provide undo (Undo) operation, among which the memo mode is used.

1.2. Definition

Memento Pattern: Without breaking the encapsulation, capture the internal state of an object and save this state outside the object, so that the object can be restored to the original saved state later. It is an object behavior pattern, its alias is Token.

2. Analysis

2.1, UML class diagram

The core of the memo pattern is the design of the memo class and the person in charge of managing memos. Its structure is shown in the figure below: It
insert image description here
can be seen that the following three roles are included in the memo pattern structure diagram:

  1. Originator: It is a common class that can create a memo and store its current internal state, or use the memo to restore its internal state. Generally, classes that need to save internal state are designed as originators.
  2. Memento: Store the internal state of the originator, and decide which internal states to save according to the originator. The design of the memo can generally refer to the design of the originator, and determine the attributes in the memo class according to actual needs. It should be noted that, except for the originator itself and the responsible person, the memo object cannot be directly used by other classes. The design of the originator will be implemented differently in different programming languages.
  3. Caretaker (person in charge): The person in charge is also called the manager. He is responsible for keeping the memorandum, but cannot operate or check the content of the memo. One or more memo objects can be stored in the person in charge, and he is only responsible for storing the objects, but cannot modify the objects, and does not need to know the implementation details of the objects.

2.2. Code example

It is not difficult to understand the memento pattern, but the key lies in how to design memento classes and responsible humans. Since the intermediate state of the originator is stored in the memo, it is necessary to prevent other objects other than the originator from accessing the memo, especially not allowing other objects to modify the memo. The following is a simple sample code to illustrate how to use the Java language to implement the memo pattern.

When using the memo pattern, there should be an originator class Originator first. In a real business, the originator class is a specific business class, which contains some attributes for storing member data. The typical code is as follows:

/**
 * @Description: 原发器类
 * @Author: yangyongbing
 * @CreateTime: 2023/08/03
 * @Version: 1.0
 */
public class Originator {
    
    

    private String state;

    public Originator() {
    
    

    }

    // 创建一个备忘录对象
    public Memento createMemento(Memento memento){
    
    
        return new Memento(this);
    }

    // 根据备忘录对象恢复原发器状态
    public void restoreMemento(Memento memento){
    
    
        state=memento.getState();
    }
    
    public String getState() {
    
    
        return state;
    }

    public void setState(String state) {
    
    
        this.state = state;
    }
}

For the memo class Memento, it usually provides attributes corresponding to the originator (it can be all or part) for storing the state of the originator. A typical memo class design code is as follows:

/**
 * @Description: 备忘录类,默认可见性,包内可见
 * @Author: yangyongbing
 * @CreateTime: 2023/08/03  12:55
 * @Version: 1.0
 */
class Memento {
    
    
    private String state;

    public Memento(Originator originator) {
    
    
        state=originator.getState();
    }

    public String getState() {
    
    
        return state;
    }

    public void setState(String state) {
    
    
        this.state = state;
    }
}

When designing the memento class, its encapsulation needs to be considered. Except for the Originator class, other classes are not allowed to call the constructor and related methods of the memento class Memento. If encapsulation is not considered, allowing other classes to call methods such as setState() will cause changes to the historical state saved in the memo, and the state restored by the undo operation will no longer be the real historical state, and the memo mode will be lost. its own meaning.

When using the Java language to implement the Memento pattern, encapsulation is generally achieved by defining the Memento class and the Originator class in the same package. In the Java language, the default access identifier can be used to define the Memento class, which ensures that it is visible in its package. Only the Originator class can access Memento, while restricting other classes' access to Memento. The state value of the Originator is saved in Memento. If the state value in the Originator needs to be revoked after being changed, it can be restored by calling its restoreMemento() method.

For the responsible human Caretaker, it is used to save the memento object, and provides the getMemento() method to return a memento object to the client. The originator can return to a certain historical state by using this memento object. A typical implementation code for humans is as follows:

/**
 * @Description: 负责人类
 * @Author: yangyongbing
 * @CreateTime: 2023/08/03  13:08
 * @Version: 1.0
 */
public class Caretaker {
    
    
    private Memento memento;

    public Memento getMemento() {
    
    
        return memento;
    }

    public void setMemento(Memento memento) {
    
    
        this.memento = memento;
    }
}

The state change method in Memento should not be called directly in the Caretaker class, and its function is only used to store the memento object. The memo object generated by the originator backup is stored in it, and the memo object stored in it is taken out when the user needs to restore the originator.

2.3. Encapsulation of the memorandum

The memo is a very special object, only the originator has control over it, and the person in charge is only responsible for managing the memo, while other classes cannot directly access the memo, so the memo needs to be encapsulated.

In order to realize the encapsulation of the memo object, it is necessary to control the calling of the memo. As far as the originator is concerned, it can recall all the information of the memento, and can access all the data needed to return to the previous state. For the person in charge, it is only responsible for saving the memo and passing the memo to other objects. For other objects, you only need to take out the memo object from the person in charge and restore the state of the originator object, without caring about the details of the memo. Ideally, only the originator that generated the memento should be allowed to access the memento's internal state.

In actual development, the relationship between the originator and the memo is very special. They need to share information without letting other classes know, and the implementation methods vary with different programming languages. In C++, you can use the friend keyword to make the originator class and the memo class a friend class, and they can access some private properties of each other. In the Java language, the originator class and the memo class can be placed in a package, so that they can meet the default visibility in the package, or the memo class can be used as the inner class of the originator class, so that only the originator Only the data in the memo can be accessed, and other objects cannot directly use the data in the memo.

3. Summary of memo mode

The memo mode is common in the use of many software, but in application software development, its use frequency is not too high, because many form-based and browser-based application software do not provide undo operations. If you need to provide software with an undo function, the memo mode is undoubtedly a good solution. The memo mode has been well applied in some word processing software, image editing software, database management system and other software.

3.1. Main advantages

  1. It provides an implementation mechanism for state recovery, so that users can easily return to a specific historical step. When the new state is invalid or has problems, the temporarily stored memo can be used to restore the state.
  2. The memo implements the encapsulation of information. A memento object is a representation of the state of the originator object and cannot be changed by other code. The memo saves the state of the originator, and using a collection such as a list or a stack to store the memo object can realize multiple undo operations.

3.2. Main disadvantages

The main disadvantage of the memo mode is: excessive resource consumption. If there are too many member variables of the originator class that need to be saved, it will inevitably take up a large amount of storage space, and a certain amount of system resources will be consumed every time the state of the object is saved.

3.3. Applicable scenarios

  1. Save all or part of the state of an object at a certain moment, so that it can be restored to the previous state when needed later, and the undo operation can be realized.
  2. Prevent external objects from destroying the encapsulation of an object's historical state, and avoid exposing the implementation details of the object's historical state to external objects.

Guess you like

Origin blog.csdn.net/YYBDESHIJIE/article/details/132081027