存档读档的Memento——备忘录模式
来源:互联网 发布:java mybatis 悲观锁 编辑:程序博客网 时间:2024/05/22 13:51
在玩游戏的时候我们总要存档、读档,
怎样实现这个功能呢?
下面是一个简单的例子:
一个Role类,用于存储角色信息
- package memento.old;
-
- public class Role {
-
- private String name;
-
- private int hp;
-
- private int mp;
-
- public Role(){
- }
-
- public Role(String name, int hp, int mp){
- this.name = name;
- this.hp = hp;
- this.mp = mp;
- }
-
- public int getHp() {
- return hp;
- }
-
- public void fight(){
- this.hp = 0;
- this.mp = 0;
- }
-
- public void setHp(int hp) {
- this.hp = hp;
- }
-
- public int getMp() {
- return mp;
- }
-
- public void setMp(int mp) {
- this.mp = mp;
- }
-
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
- }
而这个TestCase表现了它是如何实现存档读档的:
- package memento.old;
-
- import junit.framework.TestCase;
-
- public class TestGame extends TestCase {
-
- public void testGame(){
- Role role = new Role("YOYO", 100, 10);
-
- assertEquals(role.getHp(),100);
- assertEquals(role.getMp(),10);
-
- // 新建角色对象用于备份
- Role bakRole = new Role();
- bakRole.setName(role.getName());
- bakRole.setHp(role.getHp());
- bakRole.setMp(role.getMp());
-
- assertEquals(bakRole.getHp(),100);
- assertEquals(bakRole.getMp(),10);
-
- // 角色战斗
- role.fight();
- assertEquals(role.getHp(),0);
- assertEquals(role.getMp(),0);
-
- // 还原角色状态
- role.setHp(bakRole.getHp());
- role.setMp(bakRole.getMp());
-
- assertEquals(role.getHp(),100);
- assertEquals(role.getMp(),10);
- }
-
- }
这个版本中布满了set方法!
这样也许你可以直接从外部修改你的角色信息,很是危险,
正好我们已经学习了原型模式,就用clone来实现它吧?
(这里的数据结构比较简单,因此我们使用浅复制就可以了)
Role类,这回实现了一个Cloneable接口:
- package memento.clone;
-
- public class Role implements Cloneable{
-
- private String name;
-
- private int hp;
-
- private int mp;
-
- public Role(){
- }
-
- public Role(String name, int hp, int mp){
- this.name = name;
- this.hp = hp;
- this.mp = mp;
- }
-
- public int getHp() {
- return hp;
- }
-
- public int getMp() {
- return mp;
- }
-
- public String getName() {
- return name;
- }
-
- public void fight(){
- this.hp = 0;
- this.mp = 0;
- }
-
- @Override
- protected Object clone() {
- Role role = null;
- try {
- role = (Role) super.clone();
- } catch (CloneNotSupportedException e) {
- e.printStackTrace();
- }
- return role;
- }
-
- }
[TestGame]。而备份时只需要克隆它的副本就行了:
- package memento.clone;
-
- import junit.framework.TestCase;
-
- public class TestGame extends TestCase {
-
- public void testGame(){
- Role role = new Role("YOYO", 100, 10);
-
- assertEquals(role.getHp(),100);
- assertEquals(role.getMp(),10);
-
- // 新建角色对象用于备份
- Role bakRole = (Role) role.clone();
-
- assertEquals(bakRole.getHp(),100);
- assertEquals(bakRole.getMp(),10);
-
- // 角色战斗
- role.fight();
- assertEquals(role.getHp(),0);
- assertEquals(role.getMp(),0);
-
- // 还原角色状态
- role = (Role) bakRole.clone();
-
- assertEquals(role.getHp(),100);
- assertEquals(role.getMp(),10);
- }
-
- }
额,还是有点问题,
我的角色信息里不想保存角色姓名,因为它根本不会改变!
这里只是一个姓名还好,但如果有很多不需要存储的数据,使用原型模式就不大合适了。
因此,我们引入这次要讲的备忘录模式吧。
首先还是Role类,它增加了一个存档的createMemento方法和一个读档的restoreMemento方法。
- package memento.normal;
-
- public class Role {
-
- private String name;
-
- private int hp;
-
- private int mp;
-
- public Role(){
- }
-
- public Role(String name, int hp, int mp){
- this.name = name;
- this.hp = hp;
- this.mp = mp;
- }
-
- public void fight(){
- this.hp = 0;
- this.mp = 0;
- }
-
- public int getHp() {
- return hp;
- }
-
- public int getMp() {
- return mp;
- }
-
- public String getName() {
- return name;
- }
-
- public RoleMemento createMemento() {
- return new RoleMemento(name, hp, mp);
- }
-
- public void restoreMemento(RoleMemento memento) {
- name = memento.getName();
- hp = memento.getHp();
- mp = memento.getMp();
- }
-
- }
接着则是RoleMemento,角色状态存储箱,它存储了我们要保存的状态。
- package memento.normal;
-
- public class RoleMemento {
-
- private String name;
-
- private int hp;
-
- private int mp;
-
- public RoleMemento(String name, int hp, int mp){
- this.name = name;
- this.hp = hp;
- this.mp = mp;
- }
-
- public int getHp() {
- return hp;
- }
-
- public int getMp() {
- return mp;
- }
-
- public String getName() {
- return name;
- }
-
- }
除此之外,我们还需要一个Caretaker类,用来管理存档:
- package memento.normal;
-
- public class Caretaker {
-
- private RoleMemento memento;
-
- public void saveMemento(RoleMemento memento){
- this.memento = memento;
- }
-
- public RoleMemento retrieveMemento(){
- return memento;
- }
-
- }
再看看我们的TestGame,它由一个Caretaker来对指定角色进行存档和读档。
- package memento.normal;
-
- import junit.framework.TestCase;
-
- public class TestGame extends TestCase {
-
- public void testGame(){
- Role role = new Role("YOYO", 100, 10);
-
- assertEquals(role.getHp(),100);
- assertEquals(role.getMp(),10);
-
- // 新建备份
- Caretaker bak = new Caretaker();
- bak.saveMemento(role.createMemento());
-
- // 角色战斗
- role.fight();
- assertEquals(role.getHp(),0);
- assertEquals(role.getMp(),0);
-
- // 还原状态
- role.restoreMemento(bak.retrieveMemento());
-
- assertEquals(role.getHp(),100);
- assertEquals(role.getMp(),10);
- }
-
- }
这就是一个简单的备忘录模式的实现了。
数据不会被外部随意访问。
在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态。
适用性:
- 必须保存一个对象在某一个时刻的(部分)状态, 这样以后需要时它才能恢复到先前的状态。
- 如果一个用接口来让其它对象直接得到这些状态,将会暴露对象的实现细节并破坏对象的封装性。
提到备忘录模式,就不得不提到宽接口和窄接口。
在这个例子中我们可以看到,
Role类可以访问Memento内部的数据,Memento对Role提供了一个宽接口,
而对于Caretaker,它只是实现了管理Memento的作用,但并不访问Memento内部的数据,即Memento对Caretaker提供的是窄接口。
保护其内容不被发起人(Originator)对象之外的任何对象所读取。提供了两个等效的接口:宽接口和窄接口。
我们说说宽接口和窄接口的定义:
窄接口:负责人(Caretaker)对象(和其他除发起人对象之外的任何对象)看到的是备忘录的窄接口(narrow interface),这个窄接口只允许它把备忘录对象传给其他的对象。
宽接口:发起人(Originator)对象可以看到一个宽接口(wide interface),这个宽接口允许它读取所有的数据,以便根据这些数据恢复发起人对象的内部状态。
这里用的例子是一个“白箱”的实现,对于“黑箱”实现及“java实现双重接口”参见《java与模式》。
* 一个Caretaker是可以保存多个Memento的,本例为了简单所以只设计了一个。
- 存档读档的Memento——备忘录模式
- 备忘录模式——Memento
- 设计模式的征途—20.备忘录(Memento)模式
- 设计模式——备忘录模式(Memento)
- 【设计模式】—— 备忘录模式Memento
- 设计模式—Memento备忘录模式
- JAVA设计模式—备忘录模式(Memento)
- JAVA设计模式-备忘录模式-Memento-游戏备份存档
- 备忘录模式(Memento)—通风系统
- 设计模式 Design Parttern ——备忘录模式Memento
- java设计模式19——备忘录模式(Memento)
- Java设计模式——备忘录模式(Memento)
- (行为模式)MEMENTO——备忘录模式
- java设计模式——备忘录模式(Memento Pattern)
- 设计模式——备忘录(Memento Pattern)模式
- 设计模式学习笔记——备忘录(Memento)模式
- Java设计模式——备忘录模式(Memento Pattern)
- 设计模式学习笔记(十七)—Memento备忘录模式
- java.lang.String.split()中的|
- GSL - GNU Scientific Library
- 读写properties
- 终极图解内存(上篇)
- 买衣服计价问题——策略模式与OCP原则
- 存档读档的Memento——备忘录模式
- 终极图解内存(下篇)
- 糖果机的状态转换。。
- Hibernate的set排序
- Struts2中拦截器与过滤器的执行顺序
- Hibernate 使用字符串作为主键
- 使用log4j每天创建日志文件
- BREW精要之商务模式
- Swing:重置按钮的监听器实现