Memento

Memento pattern is a design where an object is able to create its own reference (the memento) for later re-assembly/re-instantiate. The idea is quite simple: before detaching or performing an operation, a "clone" action is done by copying all the states and attributes of the object into a memento. Once the operation is done, the object is re-instantiated back based on the memento.

When to Use (Problem)

  • The problem requires one object to have the capability to restore itself back to a state.
  • The problem requires one object to travel through time (backward like undo; forward like redo) between operations.
  • The problem requires one object to duplicate itself on runtime with states.

Example (Solution)

Here is a solution in Go:

package main

import (
        "fmt"
)

/****************************************************************************
 * Structure with Memento functions                                         *
 ****************************************************************************/

// Carrier is a structure with various properties
type Carrier struct {
        property1 uint
        property2 uint
        flag1     bool
}

// Clone is to create a memento of the Carrier object itself
func (c *Carrier) Clone() *Carrier {
        return &Carrier{
                property1: c.property1,
                property2: c.property2,
                flag1:     c.flag1,
        }
}

// Assimilate is to restore the Carrier object based on its mememto copy
func (c *Carrier) Assimilate(a *Carrier) {
        c.property1 = a.property1
        c.property2 = a.property2
        c.flag1 = a.flag1
}

// Print is to print the current properties' value
func (c *Carrier) Print() {
        fmt.Printf("property1: %v\n", c.property1)
        fmt.Printf("property2: %v\n", c.property2)
        fmt.Printf("flag1: %v\n", c.flag1)
        fmt.Printf("===============\n")
}

/****************************************************************************
 * Safekeeper                                                               *
 ****************************************************************************/

// SandboxConfig is the safekeeper structure to protect the memento copy of
// the Carrier objects.
type SandboxConfig struct {
        targets  []*Carrier
        mementos []*Carrier
}

// NewSandbox creates a new SandboxConfig object
func NewSandbox() *SandboxConfig {
        return &SandboxConfig{
                targets:  []*Carrier{},
                mementos: []*Carrier{},
        }
}

// Mementorize is to make a given Carrier to save its memento copy into the
// sandbox.
func (s *SandboxConfig) Mementorize(c *Carrier) {
        clone := c.Clone()
        s.targets = append(s.targets, c)
        s.mementos = append(s.mementos, clone)
}

// Restore is to restore all Carriers' values back to its original carrier.
func (s *SandboxConfig) Restore() {
        for i := range s.targets {
                x := s.targets[i]
                x.Assimilate(s.mementos[i])
        }
        s.targets = []*Carrier{}
        s.mementos = []*Carrier{}
}

func main() {
        s := NewSandbox()

        c := &Carrier{
                property1: 50,
                property2: 25,
                flag1:     true,
        }
        c.Print()
        s.Mementorize(c)

        c.property1 = 2342
        c.property2 = 2352
        c.flag1 = false
        c.Print()

        s.Restore()
        c.Print()
}

// Output:
// property1: 50
// property2: 25
// flag1: true
// ===============
// property1: 2342
// property2: 2352
// flag1: false
// ===============
// property1: 50
// property2: 25
// flag1: true
// ===============

Notice the Carrier object first mementoize itself into a sandbox. Then, it went to do its operations until it has all the properties corrupted. Once done, the sandbox restores the Carrier object properties based on its memento copy.

This design pattern is commonly seen in Sandbox testing application / implementation.

Expected Outcome (Consequences)

  1. The object is able to save its memento copy to a care taker for later restoration.
  2. The object is able to move forward into an execution and travel back to time via care taker restoration.