现在我们来学习第三种设计模式行为型的第三类,类的状态中的第一种备忘录模式,这种模式的使用场景很多,比如游戏中的存档读档。下面我们来一起学习吧。
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和例子都很容易理解的。