设计模式之备忘录模式

备忘录模式

备忘录模式

备忘录模式(Memento Pattern)又称为快照模式(Snapshot Pattern)或令牌模式(TokenPattern),是指在不破坏封装的前提下,捕获一个对象的内部状态,并在对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态,属于行为型模式。

在软件系统中,备忘录模式可以为我们提供一种“后悔药”的机制,它通过存储系统各个历史状态的快照,使得我们可以在任一时刻将系统回滚到某一个历史状态。

备忘录模式本质是从发起人实体类(Originator)隔离存储功能,降低实体类的职责。同时由于存储信息(Memeno)独力,且存储信息实体可以通过为管理类扩展额外的功能对存储信息进行扩展操作(比如增加历史快照功能…)。

通用UML图如下

image-20210427232706646

从UML类图中,我们可以看到,备忘录模式主要包含三种角色:

发起人角色(Originator):负责创建一个备忘录,记录自身需要保存的状态;具备状态回滚功能;

备忘录角色(Memento):用于存储Originator的内部状态,且可以防止Originator 以外的对象进行访问;

备忘录管理员角色(Caretaker):负责存储,提供管理备忘录(Memento),无法对备忘录内容进行操作和访问。

备忘录模的应用场景

对于我们程序员来说,可能天天都在使用备忘录模式,比如我们每天使用的Git、SVN都可以提供一种代码版本撤回的功能。还有一个比较贴切的现实场景应该是游戏的存档功能,通过将游戏当前进度存储到本地文件系统或数据库中,使得下次继续游戏时,玩家可以从之前的位置继续进行。

备忘录模式适用于以下应用场景

1、需要保存历史快照的场景

2、希望在对象之外保存状态,且除了自己其他类对象无法访问状态保存具体内容。

通用代码

备忘录角色(Memento)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Memento
{
private String state;

public String getState()
{
return state;
}

public void setState(String state)
{
this.state = state;
}
}

发起人角色(Originator)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class Originator
{
private String state;

public String getState()
{
return state;
}

public void setState(String state)
{
this.state = state;
}

public Memento createMemento()
{
Memento memento = new Memento();
memento.setState(state);
return memento;
}

public void restoreMemento(Memento memento)
{
this.state = memento.getState();
}
}

备忘录管理员角色(Caretaker)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class Caretaker
{
private Stack<Memento> mementoStack;

public Caretaker()
{
this.mementoStack = new Stack<>();
}

public Memento getMemento()
{
return mementoStack.pop();
}

public void storeMemento(Memento memento)
{
mementoStack.push(memento);
}
}

测试代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class Main
{
public static void main(String[] args)
{
Caretaker caretaker = new Caretaker();

Originator originator = new Originator();
originator.setState("a");
System.out.println(originator.getState());
caretaker.storeMemento(originator.createMemento());
originator.setState("b");
System.out.println(originator.getState());
caretaker.storeMemento(originator.createMemento());
System.out.println("恢复状态");
originator.restoreMemento(caretaker.getMemento());
System.out.println(originator.getState());
originator.restoreMemento(caretaker.getMemento());
System.out.println(originator.getState());
}
}

输出

1
2
3
4
5
6
设置状态
a
b
恢复状态
b
a

备忘录模式的优缺点

优点

1、简化发起人实体类( Originator)职责,隔离状态存储与获取,实现了信息的封装,客户端无需关心状态的保存细节

2、提供状态回滚功能

缺点

1、消耗资源,如果需要保存的状态过多时,每一次保存都会消耗很多内存

打赏

请我喝杯咖啡吧~

支付宝
微信