现在我们来学习第三种设计模式行为型的第三类,类的状态中的第一种备忘录模式,这种模式的使用场景很多,比如游戏中的存档读档。下面我们来一起学习吧。
1、备忘录模式
在不破坏封闭的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态。
使用场景: 1、需要保存/恢复数据的相关状态场景。 2、提供一个可回滚的操作。
2、涉及角色
Originator(发起人):负责创建一个备忘录Memento,用以记录当前时刻自身的内部状态,并可使用备忘录恢复内部状态。Originator可以根据需要决定Memento存储自己的哪些内部状态。Memento(备忘录):负责存储Originator对象的内部状态,并可以防止Originator以外的其他对象访问备忘录。备忘录有两个接口:Caretaker只能看到备忘录的窄接口,他只能将备忘录传递给其他对象。Originator却可看到备忘录的宽接口,允许它访问返回到先前状态所需要的所有数据。Caretaker(管理者):负责备忘录Memento,不能对Memento的内容进行访问或者操作。
3、例子
这里举一个游戏读档存档的例子,游戏中有游戏的用户姓名,游戏等级,分数。我们游戏过程中可以存档用户的等级和分数,姓名就没必要存档,以防服务器崩溃或者被BOSS杀死等级和分数重新变为0。哈哈哈真正游戏过程中当然不会因为被BOSS杀死就变为0,或者服务器崩溃变为0,这里举个例子而已。
4、UML

User是发起人:是游戏角色,可以主动存档和读档。
Memento是备忘录,这里用户每次都会新建一个备忘录,只会备忘用户的等级和分数。
Manager是管理者,可以管理备忘录,只有管理的权限不能够修改备忘录的内容。
我这里管理者只是保存一个备忘录,理论上最好用一个map来保存,然后key为用户的ID,这样子就可以管理超级多备忘录,毕竟一个游戏有超级多用户。这里举个例子就不用那么麻烦啦,主要是学会这种设计思想就可以了。
源码如下
5、Memento
/*** 备忘录* @author suibibk.com*/public class Memento {private int level;//游戏等级private int score;//分数public Memento(int level, int score) {super();this.level = level;this.score = score;}public int getLevel() {return level;}public void setLevel(int level) {this.level = level;}public int getScore() {return score;}public void setScore(int score) {this.score = score;}}
6、User
/*** 用户信息* @author suibibk.com*/public class User {private int level;//用户等级private int score;//分数private String username;//用户游戏名public int getLevel() {return level;}public void setLevel(int level) {this.level = level;}public int getScore() {return score;}public void setScore(int score) {this.score = score;}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public Memento createMemento() {return new Memento(level,score);}}
7、Manager
/*** 游戏管理者 没有修改备忘录的权限* @author suibibk.com*/public class Manager {private Memento memento;public Memento getMemento() {return memento;}public void setMemento(Memento memento) {this.memento = memento;}}
8、Test
public class Test {public static void main(String[] args) {Manager manager = new Manager();System.out.println("用户注册游戏");User user = new User();user.setLevel(3);user.setScore(20);user.setUsername("林蛋黄");System.out.println("用户修炼后游戏的等级为:"+user.getLevel()+";游戏的分数为:"+user.getScore());System.out.println("先存档");manager.setMemento(user.createMemento());user.setLevel(10);user.setScore(23);System.out.println("用户继续修炼后游戏的等级为:"+user.getLevel()+";游戏的分数为:"+user.getScore());user.setLevel(0);user.setScore(0);System.out.println("服务器崩溃了,用户的等级和分数清零等级为:"+user.getLevel()+";游戏的分数为:"+user.getScore());System.out.println("读档");Memento m = manager.getMemento();user.setLevel(m.getLevel());user.setScore(m.getScore());System.out.println("读档后等级为:"+user.getLevel()+";游戏的分数为:"+user.getScore());}}
运行输出结果如下:
用户注册游戏用户修炼后游戏的等级为:3;游戏的分数为:20先存档用户继续修炼后游戏的等级为:10;游戏的分数为:23服务器崩溃了,用户的等级和分数清零等级为:0;游戏的分数为:0读档读档后等级为:3;游戏的分数为:20
可以看到完美的实现了读档存档的效果。
9、优缺点
优点
1、给用户提供了一种可以恢复状态的机制,可以使用户能够比较方便地回到某个历史的状态。
2、实现了信息的封装,使得用户不需要关心状态的保存细节。
缺点
消耗资源。如果类的成员变量过多,势必会占用比较大的资源,而且每一次保存都会消耗一定的内存。
总结
还是很容易的也很实用的,相信看上面的UML和例子都很容易理解的。
