Skip to content

Commit 163cd63

Browse files
committed
add memento pattern
1 parent 85bb057 commit 163cd63

File tree

8 files changed

+342
-3
lines changed

8 files changed

+342
-3
lines changed

BehavioralPatterns/BehavioralPatterns.csproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@
4646
<Compile Include="Mediator\ParticipantColleague.cs" />
4747
<Compile Include="Mediator\ChatRoomMediator.cs" />
4848
<Compile Include="Mediator\TestMediator.cs" />
49+
<Compile Include="Memento\Caretaker.cs" />
50+
<Compile Include="Memento\Memento.cs" />
51+
<Compile Include="Memento\Originator.cs" />
4952
<Compile Include="NullObject\ConsoleLog.cs" />
5053
<Compile Include="NullObject\ILog.cs" />
5154
<Compile Include="NullObject\NullLog.cs" />
@@ -70,6 +73,7 @@
7073
<None Include="doc\Strategy.cd" />
7174
<None Include="doc\TemplateMethod.cd" />
7275
<None Include="Mediator\README.md" />
76+
<None Include="Memento\README.md" />
7377
<None Include="NullObject\README.md" />
7478
<None Include="Observer\README.md" />
7579
<None Include="Strategy\README.md" />
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Threading.Tasks;
6+
7+
namespace BehavioralPatterns.Memento
8+
{
9+
public class Caretaker
10+
{
11+
public static void Run()
12+
{
13+
IList<Memento> mementoes = new List<Memento>();
14+
15+
Originator originator = new Originator();
16+
originator.SetState("State 1");
17+
originator.SetState("State 2");
18+
mementoes.Add(originator.Save()); // checkpoint 1
19+
20+
originator.SetState("State 3");
21+
mementoes.Add(originator.Save()); // checkpoint 2
22+
23+
originator.SetState("State 4");
24+
originator.Restore(mementoes[0]); // restore to checkpoint 1
25+
}
26+
}
27+
}

BehavioralPatterns/Memento/Memento.cs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Threading.Tasks;
6+
7+
namespace BehavioralPatterns.Memento
8+
{
9+
[Serializable]
10+
class Memento
11+
{
12+
public string State { get; }
13+
14+
public Memento(String state)
15+
{
16+
this.State = state;
17+
}
18+
}
19+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Threading.Tasks;
6+
7+
namespace BehavioralPatterns.Memento
8+
{
9+
class Originator
10+
{
11+
private String _state;
12+
13+
public void SetState(String state)
14+
{
15+
this._state = state;
16+
Console.WriteLine($"State is set to {state}");
17+
}
18+
19+
public Memento Save()
20+
{
21+
Console.WriteLine($"Saving state to Memento");
22+
return new Memento(this._state);
23+
}
24+
25+
public void Restore(Memento m)
26+
{
27+
this._state = m.State;
28+
Console.WriteLine($"State is restored from Memento: {_state}");
29+
}
30+
}
31+
}

BehavioralPatterns/Memento/README.md

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
# Momento
2+
3+
Use the Mediator Pattern to centralize complex communications and control between related objects.
4+
5+
## Problem
6+
7+
* Tight coupling between a set of interacting objects should be avoided.
8+
* It should be possible to change the interaction between a set of objects independently.
9+
10+
*Tightly coupled objects* are hard to implement, change, test and reuse.
11+
12+
## Solution
13+
14+
* Define a `Mediator` object that encapsulates the interaction between a set of objects.
15+
* Objects delegate their interaction to a mediator object instead of interacting with each other directly.
16+
17+
This makes the objects *loosely coupled*.
18+
19+
The Mediator is commonly used to coordinate related GUI components.
20+
21+
## Benefits
22+
23+
* Colleagues classes may become more reusable and are decoupled from the system.
24+
* Simplifies maintenance of the system by centralizing control logic.
25+
* Simplifies and reduces the variety of messages sent between objects in the system.
26+
27+
## Drawbacks
28+
29+
* Without proper design, the mediator object can become overly complex.
30+
* Single point of failure
31+
* Hard to test --> Objects should be mocked
32+
33+
## Common Structure
34+
35+
![Common structure of mediator pattern](https://upload.wikimedia.org/wikipedia/commons/9/92/W3sDesign_Mediator_Design_Pattern_UML.jpg)
36+
37+
* Mediator (IChatRoom)
38+
* defines an interface for communicating with Colleague objects
39+
* ConcreteMediator (ChatRoom)
40+
* implements cooperative behavior by coordinating Colleague objects.
41+
* knows and maintains its colleagues.
42+
* Colleague (IParticipant)
43+
* defines an interface for using Colleague objects.
44+
* ConcreateColleague (Participant)
45+
* each colleague knows its Mediator object
46+
* each colleague communicates with its mediator whenever it would have otherwise communicated with another colleague.
47+
48+
_[Source: http://www.dofactory.com/net/mediator-design-pattern]_
49+
50+
## Example
51+
52+
![Mediator Pattern](/Diagrams/Mediator.png)
53+
54+
Mediator
55+
```cs
56+
public interface IChatRoom
57+
{
58+
void RegisterParticipant(IParticipant participant);
59+
void Send(String from, String to, string message);
60+
}
61+
```
62+
63+
ConcreteMediator
64+
```cs
65+
public class ChatRoom : IChatRoom
66+
{
67+
private readonly IDictionary<string, IParticipant> _participants = new Dictionary<string, IParticipant>();
68+
69+
public void RegisterParticipant(IParticipant participant)
70+
{
71+
this._participants.Add(participant.GetName(), participant);
72+
}
73+
74+
public void Send(string from, string to, string message)
75+
{
76+
if (this._participants.ContainsKey(to))
77+
{
78+
this._participants[to].Receive(from, message);
79+
}
80+
else
81+
{
82+
throw new ArgumentException("{0} not found", to);
83+
}
84+
}
85+
}
86+
```
87+
88+
Colleague
89+
```cs
90+
public interface IParticipant
91+
{
92+
string GetName();
93+
void Send(string to, string message);
94+
void Receive(string from, string message);
95+
}
96+
```
97+
98+
ConcreteColleague
99+
```cs
100+
public class Participant : IParticipant
101+
{
102+
private readonly string _name;
103+
private readonly IChatRoom _chatRoom;
104+
105+
public Participant(string name, IChatRoom chatRoom)
106+
{
107+
this._name = name;
108+
this._chatRoom = chatRoom;
109+
110+
this._chatRoom.RegisterParticipant(this);
111+
}
112+
public string GetName()
113+
{
114+
return this._name;
115+
}
116+
117+
public void Send(string to, string message)
118+
{
119+
this._chatRoom.Send(this._name, to, message);
120+
}
121+
122+
public void Receive(string from, string message)
123+
{
124+
Console.WriteLine("{0} to {1}: {2}", from, this._name, message);
125+
}
126+
}
127+
```
128+
129+
Usage
130+
```cs
131+
IChatRoom chatRoom = new ChatRoom();
132+
133+
IParticipant einstein = new Participant("Einstein", chatRoom);
134+
IParticipant newton = new Participant("Newton", chatRoom);
135+
IParticipant galileo = new Participant("Galileo", chatRoom);
136+
137+
newton.Send(galileo.GetName(), "I discoverd laws of motion");
138+
einstein.Send(newton.GetName(), "I discovered how gravity works");
139+
```

BehavioralPatterns/Momento/README.md

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
# Memento
2+
3+
The Memento pattern provides the abilitiy to restore an object to its previous state later.
4+
5+
## Problem
6+
7+
* The internal state of an object should be saved externally so that the object can be restored to this state later.
8+
* The object's encapsulation must not be violated.
9+
10+
## Solution
11+
12+
Make an object (originator) itself responsible for
13+
* saving its internal state to a `memento` object and
14+
* restoring to a previous state from a `memento` object.
15+
16+
Only the originator that created a memento is allowed to access it.
17+
18+
A client (caretaker) can request a memento from the originator to save the internal state. It can also pass a memento back to the originator to restore to a previous state.
19+
20+
## Benefits
21+
22+
* Does not violate the originator's encapsulation.
23+
* Keeping the saved state external from the originator helps to maintain cohesion.
24+
* Provides easy-to-implement recovery capability.
25+
26+
## Drawbacks
27+
28+
* Saving and restoring state can be time consuming.
29+
* It may require lots of memory if clients create mementors too often.
30+
* Clients should track the originator's lifecycle in order to destroy obsolete mementos.
31+
32+
## Common Structure
33+
34+
![Common structure of memento pattern](https://upload.wikimedia.org/wikipedia/commons/3/38/W3sDesign_Memento_Design_Pattern_UML.jpg)
35+
36+
* Memento
37+
* is a value object that stores internal state of the Originator object.
38+
* It is common practice to make Memento immutable and pass it data only once, via constructor.
39+
* Originator
40+
* creates a memento containing a snapshot of its current internal state.
41+
* uses the memento to restore its internal state
42+
* Caretaker
43+
* keeps a history of originator's state by storing a stack of mementos
44+
* never operates on or examines the contents of a memento
45+
* When originator has to go back in history, the caretaker passes the last memento to the originator's restoration method.
46+
47+
_[Source: http://www.dofactory.com/net/memento-design-pattern]_
48+
49+
## Example
50+
51+
Memento
52+
```cs
53+
[Serializable]
54+
class Memento
55+
{
56+
public string State { get; }
57+
58+
public Memento(String state)
59+
{
60+
this.State = state;
61+
}
62+
}
63+
```
64+
65+
Originator
66+
```cs
67+
class Originator
68+
{
69+
private String _state;
70+
71+
public void SetState(String state)
72+
{
73+
this._state = state;
74+
Console.WriteLine($"State is set to {state}");
75+
}
76+
77+
public Memento Save()
78+
{
79+
Console.WriteLine($"Saving state to Memento");
80+
return new Memento(this._state);
81+
}
82+
83+
public void Restore(Memento m)
84+
{
85+
this._state = m.State;
86+
Console.WriteLine($"State is restored from Memento: {_state}");
87+
}
88+
}
89+
```
90+
91+
CareTaker
92+
```cs
93+
IList<Memento> mementoes = new List<Memento>();
94+
95+
Originator originator = new Originator();
96+
originator.SetState("State 1");
97+
originator.SetState("State 2");
98+
mementoes.Add(originator.Save()); // checkpoint 1
99+
100+
originator.SetState("State 3");
101+
mementoes.Add(originator.Save()); // checkpoint 2
102+
103+
originator.SetState("State 4");
104+
originator.Restore(mementoes[0]); // restore to checkpoint 1
105+
```
106+
107+
Output
108+
```
109+
State is set to State 1
110+
State is set to State 2
111+
Saving state to Memento
112+
State is set to State 3
113+
Saving state to Memento
114+
State is set to State 4
115+
State is restored from Memento: State 2
116+
```

BehavioralPatterns/Program.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,16 @@
44
using System.Text;
55
using System.Threading.Tasks;
66
using BehavioralPatterns.Mediator;
7+
using BehavioralPatterns.Memento;
78

89
namespace BehavioralPatterns
910
{
1011
class Program
1112
{
1213
static void Main(string[] args)
1314
{
14-
TestMediator.Run();
15+
Caretaker.Run();
16+
Console.ReadKey();
1517
}
1618
}
1719
}

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ Design Patterns in C# / .NET
44
[![Build Status](https://travis-ci.org/tk-codes/DesignPatterns.NET.svg?branch=master)](https://travis-ci.org/tk-codes/DesignPatterns.NET)
55
![Language C#](https://img.shields.io/badge/language-c%23-blue.svg)
66
![status in progress](https://img.shields.io/badge/status-in%20progress-brightgreen.svg)
7-
![number of patterns](https://img.shields.io/badge/patterns-13-red.svg)
7+
![number of patterns](https://img.shields.io/badge/patterns-14-red.svg)
88

99
## Creational Patterns
1010

@@ -38,7 +38,7 @@ Design Patterns in C# / .NET
3838
| | Interpreter
3939
| | Iterator
4040
|:heavy_check_mark: | [Mediator](/BehavioralPatterns/Mediator)|
41-
| | Memento
41+
|:heavy_check_mark:| [Memento](/BehavioralPatterns/Memento)|
4242
| :heavy_check_mark: | [Null Object](/BehavioralPatterns/NullObject) |
4343
| :heavy_check_mark:| [Observer](/BehavioralPatterns/Observer/) |
4444
| | State | :warning:
@@ -51,3 +51,4 @@ Design Patterns in C# / .NET
5151
* MSDN - [Patterns & Practices](https://msdn.microsoft.com/en-us/library/ff921345.aspx)
5252
* dotFactory - http://www.dofactory.com/net/design-patterns
5353
* Wikipedia - https://en.wikipedia.org/wiki/Software_design_pattern
54+
* Refactoring.Guru - https://refactoring.guru/design-patterns

0 commit comments

Comments
 (0)