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 << " \n Caretaker: 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 << " \n Client: Now, let's rollback!\n\n " ;
240+ caretaker->Undo ();
241+ std::cout << " \n Client: 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