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.
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.