Skip to content

Commit 36a6a19

Browse files
authored
Merge pull request #9 from sensorario/memento
start studying memento pattern
2 parents 974335a + a3e8819 commit 36a6a19

File tree

5 files changed

+155
-0
lines changed

5 files changed

+155
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
* [Strategy](behavioral/strategy) [:notebook:](https://en.wikipedia.org/wiki/Strategy_pattern)
1111
* [Command](behavioral/command) [:notebook:](https://en.wikipedia.org/wiki/Command_pattern)
1212
* [Template](behavioral/template) [:notebook:](https://en.wikipedia.org/wiki/Template_pattern)
13+
* [Memento](behavioral/memento) [:notebook:](https://en.wikipedia.org/wiki/Memento_pattern)
1314

1415
## [Creational](creational)
1516

behavioral/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@ We are going to deal with behaviors instead of define structures or encapsulate
88
* [Chain of Responsibility](chain) [:notebook:](https://en.wikipedia.org/wiki/Chain-of-responsibility_pattern)
99
* [Command](command) [:notebook:](https://en.wikipedia.org/wiki/Command_pattern)
1010
* [Template](template) [:notebook:](https://en.wikipedia.org/wiki/Template_pattern)
11+
* [Memento](memento) [:notebook:](https://en.wikipedia.org/wiki/Memento_pattern)

behavioral/memento/README.md

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# Behavioral » Memento
2+
3+
## Description
4+
5+
The memento pattern provides the ability to restore an object to of its
6+
previous state (undo via rollback). It is implemented with three elements:
7+
8+
- memento
9+
- originator
10+
- caretaker
11+
12+
The `memento` is an extra-layer not yet saved. The `originator` is a type in
13+
charge to build/create the mementos. Finally, the `caretaker` is the type that
14+
stores the lists of mementos.
15+
16+
## Implementation
17+
18+
Every time we create new memento object, its state is taken from the originator
19+
element of the design pattern.
20+
21+
```go
22+
func TestNewMementoTakeOriginatorState(t *testing.T) {
23+
firstState := originator{}
24+
firstState.state = State{Description: "Idle"}
25+
mem := firstState.NewMemento()
26+
if mem.state.Description != "Idle" {
27+
t.Error("Expected state was not found")
28+
}
29+
}
30+
31+
func (o *originator) NewMemento() memento {
32+
return memento{state: o.state}
33+
}
34+
```
35+
In the following test state is changed to "working" to ensure that new state
36+
will be written.
37+
38+
```go
39+
func TestStoresIdleState(t *testing.T) {
40+
originator := originator{state: State{"Idle"}}
41+
idleMemento := originator.NewMemento()
42+
originator.state.Description = "Working"
43+
originator.ExtractAndStoreState(idleMemento)
44+
if originator.state.Description != "Idle" {
45+
t.Error("Unexpected state found")
46+
}
47+
}
48+
```

behavioral/memento/memento.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
)
6+
7+
type State struct {
8+
Description string
9+
}
10+
11+
type memento struct {
12+
state State
13+
}
14+
15+
type originator struct {
16+
state State
17+
}
18+
19+
func (o *originator) NewMemento() memento {
20+
return memento{state: o.state}
21+
}
22+
23+
func (o *originator) ExtractAndStoreState(m memento) {
24+
o.state = m.state
25+
}
26+
27+
type careTaker struct {
28+
mementoList []memento
29+
}
30+
31+
func (c *careTaker) Add(m memento) {
32+
c.mementoList = append(c.mementoList, m)
33+
}
34+
35+
func (c *careTaker) Memento(i int) (memento, error) {
36+
if i < 0 {
37+
return memento{}, fmt.Errorf("Index not found")
38+
}
39+
return c.mementoList[i], nil
40+
}

behavioral/memento/memento_test.go

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package main
2+
3+
import (
4+
"testing"
5+
)
6+
7+
func TestNewMementoTakeOriginatorState(t *testing.T) {
8+
firstState := originator{}
9+
firstState.state = State{Description: "Idle"}
10+
mem := firstState.NewMemento()
11+
if mem.state.Description != "Idle" {
12+
t.Error("Expected state was not found")
13+
}
14+
}
15+
16+
func TestCareTakerKeepAlMementoInsideAList(t *testing.T) {
17+
firstState := originator{}
18+
firstState.state = State{Description: "Idle"}
19+
mem := firstState.NewMemento()
20+
careTaker := careTaker{}
21+
lenBeforeAddedMemento := len(careTaker.mementoList)
22+
careTaker.Add(mem)
23+
if len(careTaker.mementoList) != lenBeforeAddedMemento+1 {
24+
t.Errorf("No new elements were added on the list")
25+
}
26+
}
27+
28+
func TestCareTaker(t *testing.T) {
29+
originator := originator{}
30+
careTaker := careTaker{}
31+
originator.state = State{"foo"}
32+
careTaker.Add(originator.NewMemento())
33+
mem, err := careTaker.Memento(0)
34+
if err != nil {
35+
t.Fatal(err)
36+
}
37+
if mem.state.Description != "foo" {
38+
t.Error("Unexpected state")
39+
}
40+
}
41+
42+
func TestCareTakerDetectIfNonExistentIndexIsRequested(t *testing.T) {
43+
originator := originator{}
44+
careTaker := careTaker{}
45+
originator.state = State{"foo"}
46+
careTaker.Add(originator.NewMemento())
47+
_, err := careTaker.Memento(0)
48+
if err != nil {
49+
t.Fatal(err)
50+
}
51+
_, err = careTaker.Memento(-1)
52+
if err == nil {
53+
t.Fatal("An error is expected")
54+
}
55+
}
56+
57+
func TestStoresIdleState(t *testing.T) {
58+
originator := originator{state: State{"Idle"}}
59+
idleMemento := originator.NewMemento()
60+
originator.state.Description = "Working"
61+
originator.ExtractAndStoreState(idleMemento)
62+
if originator.state.Description != "Idle" {
63+
t.Error("Unexpected state found")
64+
}
65+
}

0 commit comments

Comments
 (0)