Memento Design Pattern in Go: Capture and Restore Object State

Explore the Memento design pattern in Go, its intent, implementation, and use cases, including undo/redo functionality in applications.

2.3.6 Memento

The Memento design pattern is a behavioral pattern that allows capturing and externalizing an object’s internal state without violating encapsulation. This pattern provides the ability to restore the object to a previous state, making it particularly useful for implementing undo/redo functionality in applications.

Understand the Intent

The primary intent of the Memento pattern is to:

  • Capture an Object’s Internal State: Safely store the state of an object so that it can be restored later.
  • Restore the Object to a Previous State: Allow the object to revert to a previous state without exposing its internal structure.

Implementation Steps

The Memento pattern involves three main components:

  1. Originator:

    • This is the object whose state needs to be saved and restored.
    • It implements methods to create and set mementos.
  2. Memento:

    • A struct that stores the state of the originator.
    • It is typically opaque to other objects, ensuring encapsulation.
  3. Caretaker:

    • Manages the saving and restoring of mementos.
    • Holds mementos but does not manipulate or inspect them.

Below is a conceptual diagram illustrating the Memento pattern:

    classDiagram
	    class Originator {
	        -state: State
	        +createMemento(): Memento
	        +setMemento(m: Memento)
	    }
	
	    class Memento {
	        -state: State
	        +getState(): State
	    }
	
	    class Caretaker {
	        -mementos: list~Memento~
	        +addMemento(m: Memento)
	        +getMemento(index: int): Memento
	    }
	
	    Originator --> Memento
	    Caretaker --> Memento

When to Use

The Memento pattern is particularly useful in scenarios such as:

  • Implementing Undo/Redo Functionality: Allows users to revert changes or redo actions in applications like text editors.
  • Snapshotting State: When snapshots of an object’s state are required for rollback or auditing purposes.

Go-Specific Tips

  • Immutability: Ensure that mementos are immutable after creation to maintain consistency and reliability.
  • Serialization: Carefully serialize the state if the memento will be stored externally, ensuring data integrity and security.

Example: Text Editor with Undo/Redo

Let’s consider a simple text editor application where users can undo and redo changes to the text content.

 1package main
 2
 3import "fmt"
 4
 5// Memento stores the state of the Originator
 6type Memento struct {
 7	state string
 8}
 9
10// Originator is the object whose state needs to be saved and restored
11type Originator struct {
12	state string
13}
14
15func (o *Originator) CreateMemento() Memento {
16	return Memento{state: o.state}
17}
18
19func (o *Originator) RestoreMemento(m Memento) {
20	o.state = m.state
21}
22
23func (o *Originator) SetState(state string) {
24	o.state = state
25}
26
27func (o *Originator) GetState() string {
28	return o.state
29}
30
31// Caretaker manages the mementos
32type Caretaker struct {
33	mementos []Memento
34}
35
36func (c *Caretaker) AddMemento(m Memento) {
37	c.mementos = append(c.mementos, m)
38}
39
40func (c *Caretaker) GetMemento(index int) Memento {
41	return c.mementos[index]
42}
43
44func main() {
45	originator := &Originator{}
46	caretaker := &Caretaker{}
47
48	originator.SetState("State 1")
49	caretaker.AddMemento(originator.CreateMemento())
50
51	originator.SetState("State 2")
52	caretaker.AddMemento(originator.CreateMemento())
53
54	originator.SetState("State 3")
55	fmt.Println("Current State:", originator.GetState())
56
57	originator.RestoreMemento(caretaker.GetMemento(1))
58	fmt.Println("Restored to State:", originator.GetState())
59
60	originator.RestoreMemento(caretaker.GetMemento(0))
61	fmt.Println("Restored to State:", originator.GetState())
62}

Advantages and Disadvantages

Advantages:

  • Encapsulation: Maintains encapsulation boundaries by not exposing the internal state of objects.
  • Flexibility: Provides a flexible way to manage state history and restore previous states.

Disadvantages:

  • Memory Overhead: Can consume significant memory if many mementos are stored.
  • Complexity: Adds complexity to the system, especially when managing multiple mementos.

Best Practices

  • Limit Mementos: Store only necessary mementos to reduce memory usage.
  • Immutable Mementos: Ensure mementos are immutable to prevent accidental modifications.
  • Efficient State Storage: Use efficient data structures and serialization techniques for state storage.

Comparisons

The Memento pattern is often compared with the Command pattern, which can also implement undo functionality. However, the Command pattern focuses on encapsulating operations, while the Memento pattern encapsulates state.

Conclusion

The Memento design pattern is a powerful tool for managing object state in Go applications, particularly when implementing undo/redo functionality. By capturing and restoring state without violating encapsulation, developers can create flexible and user-friendly applications.

Quiz Time!

Loading quiz…
Revised on Thursday, April 23, 2026