Skip to content

Commit ef3dcd7

Browse files
Eder DuranEder Duran
authored andcommitted
Memento design pattern
1 parent 80889d3 commit ef3dcd7

2 files changed

Lines changed: 286 additions & 0 deletions

File tree

src/Memento/Conceptual/Output.txt

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
Originator: My initial state is: Super-duper-super-puper-super.
2+
3+
Caretaker: Saving Originator's state...
4+
Originator: I'm doing something important.
5+
Originator: and my state has changed to: uOInE8wmckHYPwZS7PtUTwuwZfCIbz
6+
7+
Caretaker: Saving Originator's state...
8+
Originator: I'm doing something important.
9+
Originator: and my state has changed to: te6RGmykRpbqaWo5MEwjji1fpM1t5D
10+
11+
Caretaker: Saving Originator's state...
12+
Originator: I'm doing something important.
13+
Originator: and my state has changed to: hX5xWDVljcQ9ydD7StUfbBt5Z7pcSN
14+
15+
Caretaker: Here's the list of mementos:
16+
Sat Oct 19 18:09:37 2019
17+
/ (Super-dup...)
18+
Sat Oct 19 18:09:37 2019
19+
/ (uOInE8wmc...)
20+
Sat Oct 19 18:09:37 2019
21+
/ (te6RGmykR...)
22+
23+
Client: Now, let's rollback!
24+
25+
Caretaker: Restoring state to: Sat Oct 19 18:09:37 2019
26+
/ (te6RGmykR...)
27+
Originator: My state has changed to: te6RGmykRpbqaWo5MEwjji1fpM1t5D
28+
29+
Client: Once more!
30+
31+
Caretaker: Restoring state to: Sat Oct 19 18:09:37 2019
32+
/ (uOInE8wmc...)
33+
Originator: My state has changed to: uOInE8wmckHYPwZS7PtUTwuwZfCIbz

src/Memento/Conceptual/main.cc

Lines changed: 253 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,253 @@
1+
#include <string>
2+
#include <iostream>
3+
#include <cstdlib>
4+
#include <ctime>
5+
#include <vector>
6+
7+
/**
8+
* EN: Memento Design Pattern
9+
*
10+
* Intent: Lets you save and restore the previous state of an object without
11+
* revealing the details of its implementation.
12+
*
13+
* RU: Паттерн Снимок
14+
*
15+
* Назначение: Фиксирует и восстанавливает внутреннее состояние объекта таким
16+
* образом, чтобы в дальнейшем объект можно было восстановить в этом состоянии
17+
* без нарушения инкапсуляции.
18+
*/
19+
20+
/**
21+
* EN: The Memento interface provides a way to retrieve the memento's metadata,
22+
* such as creation date or name. However, it doesn't expose the Originator's
23+
* state.
24+
*
25+
* RU: Интерфейс Снимка предоставляет способ извлечения метаданных снимка, таких
26+
* как дата создания или название. Однако он не раскрывает состояние Создателя.
27+
*/
28+
class Memento
29+
{
30+
public:
31+
virtual std::string GetName() const = 0;
32+
virtual std::string date() const = 0;
33+
virtual std::string state() const = 0;
34+
};
35+
36+
/**
37+
* EN: The Concrete Memento contains the infrastructure for storing the
38+
* Originator's state.
39+
*
40+
* RU: Конкретный снимок содержит инфраструктуру для хранения состояния
41+
* Создателя.
42+
*/
43+
class ConcreteMemento : public Memento
44+
{
45+
private:
46+
std::string state_;
47+
std::string date_;
48+
49+
public:
50+
ConcreteMemento(std::string state) : state_(state)
51+
{
52+
this->state_ = state;
53+
std::time_t now = std::time(0);
54+
this->date_ = std::ctime(&now);
55+
}
56+
/**
57+
* EN: The Originator uses this method when restoring its state.
58+
*
59+
* RU: Создатель использует этот метод, когда восстанавливает своё
60+
* состояние.
61+
*/
62+
std::string state() const override
63+
{
64+
return this->state_;
65+
}
66+
/**
67+
* EN: The rest of the methods are used by the Caretaker to display
68+
* metadata.
69+
*
70+
* RU: Остальные методы используются Опекуном для отображения метаданных.
71+
*/
72+
std::string GetName() const override
73+
{
74+
return this->date_ + " / (" + this->state_.substr(0, 9) + "...)";
75+
}
76+
std::string date() const override
77+
{
78+
return this->date_;
79+
}
80+
};
81+
82+
/**
83+
* EN: The Originator holds some important state that may change over time. It
84+
* also defines a method for saving the state inside a memento and another
85+
* method for restoring the state from it.
86+
*
87+
* RU: Создатель содержит некоторое важное состояние, которое может со временем
88+
* меняться. Он также объявляет метод сохранения состояния внутри снимка и метод
89+
* восстановления состояния из него.
90+
*/
91+
class Originator
92+
{
93+
/**
94+
* EN: @var string For the sake of simplicity, the originator's state is
95+
* stored inside a single variable.
96+
*
97+
* RU: @var string Для удобства состояние создателя хранится внутри одной
98+
* переменной.
99+
*/
100+
private:
101+
std::string state_;
102+
103+
std::string GenerateRandomString(int length = 10)
104+
{
105+
const char alphanum[] =
106+
"0123456789"
107+
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
108+
"abcdefghijklmnopqrstuvwxyz";
109+
int stringLength = sizeof(alphanum) - 1;
110+
111+
std::string random_string;
112+
for (int i = 0; i < length; i++)
113+
{
114+
random_string += alphanum[std::rand() % stringLength];
115+
}
116+
return random_string;
117+
}
118+
119+
public:
120+
Originator(std::string state) : state_(state)
121+
{
122+
std::cout << "Originator: My initial state is: " << this->state_ << "\n";
123+
}
124+
/**
125+
* EN: The Originator's business logic may affect its internal state.
126+
* Therefore, the client should backup the state before launching methods of
127+
* the business logic via the save() method.
128+
*
129+
* RU: Бизнес-логика Создателя может повлиять на его внутреннее состояние.
130+
* Поэтому клиент должен выполнить резервное копирование состояния с помощью
131+
* метода save перед запуском методов бизнес-логики.
132+
*/
133+
void DoSomething()
134+
{
135+
std::cout << "Originator: I'm doing something important.\n";
136+
this->state_ = this->GenerateRandomString(30);
137+
std::cout << "Originator: and my state has changed to: " << this->state_ << "\n";
138+
}
139+
140+
/**
141+
* EN: Saves the current state inside a memento.
142+
*
143+
* RU: Сохраняет текущее состояние внутри снимка.
144+
*/
145+
Memento *Save()
146+
{
147+
return new ConcreteMemento(this->state_);
148+
}
149+
/**
150+
* EN: Restores the Originator's state from a memento object.
151+
*
152+
* RU: Восстанавливает состояние Создателя из объекта снимка.
153+
*/
154+
void Restore(Memento *memento)
155+
{
156+
this->state_ = memento->state();
157+
std::cout << "Originator: My state has changed to: " << this->state_ << "\n";
158+
}
159+
};
160+
161+
/**
162+
* EN: The Caretaker doesn't depend on the Concrete Memento class. Therefore, it
163+
* doesn't have access to the originator's state, stored inside the memento. It
164+
* works with all mementos via the base Memento interface.
165+
*
166+
* RU: Опекун не зависит от класса Конкретного Снимка. Таким образом, он не
167+
* имеет доступа к состоянию создателя, хранящемуся внутри снимка. Он работает
168+
* со всеми снимками через базовый интерфейс Снимка.
169+
*/
170+
class Caretaker
171+
{
172+
/**
173+
* @var Memento[]
174+
*/
175+
private:
176+
std::vector<Memento *> mementos_;
177+
178+
/**
179+
* @var Originator
180+
*/
181+
Originator *originator_;
182+
183+
public:
184+
Caretaker(Originator *originator) : originator_(originator)
185+
{
186+
this->originator_ = originator;
187+
}
188+
189+
void Backup()
190+
{
191+
std::cout << "\nCaretaker: Saving Originator's state...\n";
192+
this->mementos_.push_back(this->originator_->Save());
193+
}
194+
void Undo()
195+
{
196+
if (!this->mementos_.size())
197+
{
198+
return;
199+
}
200+
Memento *memento = this->mementos_.back();
201+
this->mementos_.pop_back();
202+
std::cout << "Caretaker: Restoring state to: " << memento->GetName() << "\n";
203+
try
204+
{
205+
this->originator_->Restore(memento);
206+
}
207+
catch (...)
208+
{
209+
this->Undo();
210+
}
211+
}
212+
void ShowHistory() const
213+
{
214+
std::cout << "Caretaker: Here's the list of mementos:\n";
215+
for (Memento *memento : this->mementos_)
216+
{
217+
std::cout << memento->GetName() << "\n";
218+
}
219+
}
220+
};
221+
/**
222+
* EN: Client code.
223+
*
224+
* RU: Клиентский код.
225+
*/
226+
227+
void ClientCode()
228+
{
229+
Originator *originator = new Originator("Super-duper-super-puper-super.");
230+
Caretaker *caretaker = new Caretaker(originator);
231+
caretaker->Backup();
232+
originator->DoSomething();
233+
caretaker->Backup();
234+
originator->DoSomething();
235+
caretaker->Backup();
236+
originator->DoSomething();
237+
std::cout << "\n";
238+
caretaker->ShowHistory();
239+
std::cout << "\nClient: Now, let's rollback!\n\n";
240+
caretaker->Undo();
241+
std::cout << "\nClient: Once more!\n\n";
242+
caretaker->Undo();
243+
244+
delete originator;
245+
delete caretaker;
246+
}
247+
248+
int main()
249+
{
250+
std::srand(static_cast<unsigned int>(std::time(NULL)));
251+
ClientCode();
252+
return 0;
253+
}

0 commit comments

Comments
 (0)