Skip to content

Commit 723e29b

Browse files
author
Jarry
committed
add memento for c
1 parent e78e605 commit 723e29b

File tree

7 files changed

+336
-3
lines changed

7 files changed

+336
-3
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,4 +100,4 @@ Implemented in different languages, including Java/JS/Python/TypeScript/Go, etc.
100100
### Contact 联系
101101
欢迎共建 Welcome to join
102102
- Wechat: **springbuild**
103-
- QQ: **12263529**
103+
- QQ: **12263539**

memento-pattern/README.md

Lines changed: 139 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# 【备忘录设计模式详解】Java/JS/Go/Python/TS不同语言实现
1+
# 【备忘录设计模式详解】C/Java/JS/Go/Python/TS不同语言实现
22

33
# 简介
44
备忘录模式(Memento Pattern)是一种结构型设计模式。这种模式就是在不破坏封装的条件下,将一个对象的状态捕捉(Capture)住,并放在外部存储起来,从而可以在将来合适的时候把这个对象还原到存储起来的状态。备忘录模式常常与命令模式和迭代子模式一同使用。
@@ -23,7 +23,7 @@
2323
# UML
2424
<img src="../docs/uml/memento-pattern.png">
2525

26-
# 代码
26+
# Java代码
2727

2828
## 具体备忘录
2929
```java
@@ -135,5 +135,142 @@ public class Caretaker {
135135
System.out.println("state: " + i + ")" + originator.getState());
136136
}
137137
```
138+
139+
# JavaScript代码
140+
141+
## 具体备忘录
142+
```js
143+
// Memento.js 备忘录(Memento)角色,负责存储发起人传入的状态
144+
// 备忘录(Memento)角色,负责存储发起人传入的状态
145+
export class Memento {
146+
constructor(state) {
147+
console.log(this.constructor.name + '::Memento() [state = ' + state + ']')
148+
this.state = state
149+
}
150+
151+
getState() {
152+
return this.state
153+
}
154+
155+
setState(state) {
156+
this.state = state
157+
}
158+
}
159+
160+
```
161+
162+
## 发起人
163+
```js
164+
// Originator.js 发起人(Originator)负责生成状态快照,即利用一个新备忘录对象将自己的内部状态存储起来
165+
import { Memento } from './Memento.js'
166+
167+
export class Originator {
168+
constructor() {
169+
this.state = undefined
170+
}
171+
172+
// 每次创建一个新备忘录来保存状态
173+
saveMemento() {
174+
console.log(
175+
this.constructor.name + '::saveMemento() [state = ' + this.state + ']'
176+
)
177+
return new Memento(this.state)
178+
}
179+
180+
// 从备忘录中恢复状态
181+
restoreMemento(memento) {
182+
this.state = memento.getState()
183+
}
184+
185+
getState() {
186+
return this.state
187+
}
188+
189+
setState(state) {
190+
this.state = state
191+
}
192+
}
193+
```
194+
195+
## 负责人类
196+
```js
197+
// Caretaker.js 负责人(Caretaker)角色,只负责保存备忘录记录,不能修改备忘录对象的内容
198+
export class Caretaker {
199+
constructor() {
200+
// 备忘录可以是一个记录,也可以就是一个对象,根据业务场景设置
201+
this.mementoList = []
202+
}
203+
204+
add(memento) {
205+
console.log(
206+
this.constructor.name +
207+
'::add() [memento = ' +
208+
memento.constructor.name +
209+
']'
210+
)
211+
this.mementoList.push(memento)
212+
}
213+
214+
get(index) {
215+
return this.mementoList[index]
216+
}
217+
218+
getMementoList() {
219+
return this.mementoList
220+
}
221+
}
222+
```
223+
224+
## 测试调用
225+
```js
226+
import { Originator } from '../src/Originator.js'
227+
import { Caretaker } from '../src/Caretaker.js'
228+
229+
export function test() {
230+
/*
231+
* 备忘录模式是在不暴露对象实现细节的情况下保存和恢复对象之前的状态。
232+
* 先声明发起人Originator,再声明负责人Caretaker,发起人生成备忘录Memento
233+
* 通过负责人则保存备忘录历史记录,读取备忘录由负责人来完成。
234+
*/
235+
const originator = new Originator()
236+
const careTaker = new Caretaker()
237+
// 发起人产生一个状态
238+
originator.setState('state1')
239+
// 覆盖了状态,那么前面的状态未保存
240+
originator.setState('state2')
241+
// 发起人生成备忘录,一般添加时直接保存即可
242+
const memento = originator.saveMemento()
243+
// 负责人保添加备忘录历史记录
244+
careTaker.add(memento)
245+
246+
// 直接生成备忘录并添加到负责人的备忘录列表
247+
originator.setState('state3')
248+
careTaker.add(originator.saveMemento())
249+
originator.setState('state4')
250+
careTaker.add(originator.saveMemento())
251+
252+
console.log('发起人当前的状态: ' + originator.getState())
253+
254+
// 发起人通过负责人那里取出状态
255+
originator.restoreMemento(careTaker.get(0))
256+
console.log('第一个保存的状态: ' + originator.getState())
257+
originator.restoreMemento(careTaker.get(1))
258+
console.log('第二个保存的状态: ' + originator.getState())
259+
260+
// 遍历全部备忘录
261+
for (let i = 0; i < careTaker.getMementoList().length; i++) {
262+
// 外部一般不直接访问备忘录里面的状态,而是逐个恢复备忘录,再取出状态来
263+
originator.restoreMemento(careTaker.get(i))
264+
console.log('state: ' + i + ')' + originator.getState())
265+
}
266+
}
267+
268+
// 执行测试
269+
;(function () {
270+
console.log('test start:')
271+
test()
272+
})()
273+
```
274+
138275
## 更多语言版本
139276
不同语言实现设计模式:[https://github.com/microwind/design-pattern](https://github.com/microwind/design-pattern)

memento-pattern/c/src/caretaker.c

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#include "func.h"
2+
3+
void caretaker_add(Caretaker *caretaker, Memento *memento)
4+
{
5+
printf("\r\n Caretaker::add() [memento = %s]", memento->name);
6+
caretaker->memento_length += 1;
7+
Memento **new_memento_list = (Memento **)calloc(caretaker->memento_length, sizeof(Memento));
8+
// 复制原有数组,并追加新内容到新数组
9+
for (int i = 0; i < caretaker->memento_length - 1; i++)
10+
{
11+
new_memento_list[i] = caretaker->memento_list[i];
12+
}
13+
new_memento_list[caretaker->memento_length - 1] = memento;
14+
free(caretaker->memento_list);
15+
// 指向新数组
16+
caretaker->memento_list = new_memento_list;
17+
}
18+
19+
Memento *caretaker_get(Caretaker *caretaker, int index)
20+
{
21+
return caretaker->memento_list[index];
22+
}
23+
24+
// 负责人(Caretaker)角色,只负责保存备忘录记录,不能修改备忘录对象的内容
25+
Caretaker *caretaker_constructor()
26+
{
27+
printf("\r\n caretaker_constructor() [构建Caretaker]");
28+
Caretaker *caretaker = (Caretaker *)malloc(sizeof(Caretaker));
29+
caretaker->add = &caretaker_add;
30+
caretaker->get = &caretaker_get;
31+
return caretaker;
32+
}

memento-pattern/c/src/func.h

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#include <stdio.h>
2+
#include <ctype.h>
3+
#include <stdlib.h>
4+
#include <stdbool.h>
5+
#include <string.h>
6+
7+
// 备忘录(Memento)角色,负责存储发起人传入的状态
8+
typedef struct Memento
9+
{
10+
char name[50];
11+
char state[50];
12+
void (*set_state)(struct Memento *memento, char *state);
13+
char *(*get_state)(struct Memento *memento);
14+
} Memento;
15+
Memento *memento_constructor(char *name, char *state);
16+
17+
// 负责人(Caretaker)角色,只负责保存备忘录记录,不能修改备忘录对象的内容
18+
typedef struct Caretaker
19+
{
20+
Memento **memento_list;
21+
int memento_length;
22+
void (*add)(struct Caretaker *caretaker, Memento *memento);
23+
Memento *(*get)(struct Caretaker *caretaker, int index);
24+
} Caretaker;
25+
Caretaker *caretaker_constructor();
26+
27+
// 发起人(Originator)负责生成状态快照,即利用一个新备忘录对象将自己的内部状态存储起来
28+
typedef struct Originator
29+
{
30+
char state[50];
31+
struct Memento *(*save_memento)(struct Originator *originator);
32+
void (*restore_memento)(struct Originator *originator, struct Memento *memento);
33+
void (*set_state)(struct Originator *originator, char *state);
34+
char *(*get_state)(struct Originator *originator);
35+
} Originator;
36+
Originator *originator_constructor();

memento-pattern/c/src/memento.c

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#include "func.h"
2+
3+
char *get_state(Memento *m)
4+
{
5+
return m->state;
6+
}
7+
8+
void set_state(Memento *m, char *state)
9+
{
10+
strncpy(m->state, state, 50);
11+
}
12+
13+
// 备忘录(Memento)角色,负责存储发起人传入的状态
14+
Memento *memento_constructor(char *name, char *state)
15+
{
16+
printf("\r\n memento_constructor() [构建Memento name=%s state=%s]", name, state);
17+
Memento *memento = (Memento *)malloc(sizeof(Memento));
18+
strncpy(memento->name, name, 50);
19+
strncpy(memento->state, state, 50);
20+
memento->get_state = &get_state;
21+
memento->set_state = &set_state;
22+
return memento;
23+
}

memento-pattern/c/src/originator.c

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
#include "func.h"
2+
3+
// 每次创建一个新备忘录来保存状态
4+
Memento *originator_save_memento(Originator *originator)
5+
{
6+
printf("\r\n Originator::save_memento() [state = %s]", originator->state);
7+
Memento *memento = memento_constructor("Memento", originator->state);
8+
return memento;
9+
}
10+
11+
// 从备忘录中恢复状态
12+
void originator_restore_memento(Originator *originator, Memento *memento)
13+
{
14+
strncpy(originator->state, memento->get_state(memento), 50);
15+
}
16+
17+
void originator_set_state(Originator *originator, char *state)
18+
{
19+
strncpy(originator->state, state, 50);
20+
}
21+
22+
char *originator_get_state(Originator *originator)
23+
{
24+
return originator->state;
25+
}
26+
27+
// 发起人(Originator)负责生成状态快照,即利用一个新备忘录对象将自己的内部状态存储起来
28+
Originator *originator_constructor()
29+
{
30+
printf("\r\n originator_constructor() [构建通用聊天室]");
31+
Originator *originator = (Originator *)malloc(sizeof(Originator));
32+
originator->save_memento = &originator_save_memento;
33+
originator->restore_memento = &originator_restore_memento;
34+
originator->set_state = &originator_set_state;
35+
originator->get_state = &originator_get_state;
36+
return originator;
37+
}

memento-pattern/c/test/test.c

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
#include "../src/func.h"
2+
3+
int main(void)
4+
{
5+
printf("test start:\r\n");
6+
/*
7+
* 备忘录模式是在不暴露对象实现细节的情况下保存和恢复对象之前的状态。
8+
* 先声明发起人Originator,再声明负责人Caretaker,发起人生成备忘录Memento
9+
* 通过负责人则保存备忘录历史记录,读取备忘录由负责人来完成。
10+
*/
11+
Originator *originator = originator_constructor();
12+
Caretaker *caretaker = caretaker_constructor();
13+
// 发起人产生一个状态
14+
originator->set_state(originator, "state1");
15+
// 覆盖了状态,那么前面的状态未保存
16+
originator->set_state(originator, "state2");
17+
// 发起人生成备忘录,一般添加时直接保存即可
18+
Memento *memento = originator->save_memento(originator);
19+
// 负责人保添加备忘录历史记录
20+
caretaker->add(caretaker, memento);
21+
22+
// 直接生成备忘录并添加到负责人的备忘录列表
23+
originator->set_state(originator, "state3");
24+
caretaker->add(caretaker, originator->save_memento(originator));
25+
originator->set_state(originator, "state4");
26+
caretaker->add(caretaker, originator->save_memento(originator));
27+
28+
printf("\r\n 发起人当前的状态: %s", originator->get_state(originator));
29+
30+
// 发起人通过负责人那里取出状态
31+
originator->restore_memento(originator, caretaker->get(caretaker, 0));
32+
printf("\r\n 第一个保存的状态: %s", originator->get_state(originator));
33+
originator->restore_memento(originator, caretaker->get(caretaker, 1));
34+
printf("\r\n 第二个保存的状态: %s", originator->get_state(originator));
35+
36+
printf("\r\n 遍历全部备忘录:");
37+
for (int i = 0; i < caretaker->memento_length; i++)
38+
{
39+
// 外部一般不直接访问备忘录里面的状态,而是逐个恢复备忘录,再取出状态来
40+
originator->restore_memento(originator, caretaker->get(caretaker, i));
41+
printf("\r\n %d) state=%s", i, originator->get_state(originator));
42+
}
43+
}
44+
45+
/**
46+
jarry@jarrys-MacBook-Pro c % gcc test/test.c ./src下*.c
47+
jarry@jarrys-MacBook-Pro c % ./a.out
48+
test start:
49+
50+
originator_constructor() [构建通用聊天室]
51+
caretaker_constructor() [构建Caretaker]
52+
Originator::save_memento() [state = state2]
53+
memento_constructor() [构建Memento name=Memento state=state2]
54+
Caretaker::add() [memento = Memento]
55+
Originator::save_memento() [state = state3]
56+
memento_constructor() [构建Memento name=Memento state=state3]
57+
Caretaker::add() [memento = Memento]
58+
Originator::save_memento() [state = state4]
59+
memento_constructor() [构建Memento name=Memento state=state4]
60+
Caretaker::add() [memento = Memento]
61+
发起人当前的状态: state4
62+
第一个保存的状态: state2
63+
第二个保存的状态: state3
64+
遍历全部备忘录:
65+
0) state=state2
66+
1) state=state3
67+
2) state=state4%
68+
*/

0 commit comments

Comments
 (0)