欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

简说设计模式——备忘录模式

程序员文章站 2022-07-02 22:39:16
一、什么是备忘录模式 备忘录这个词汇大家应该都不陌生,我就经常使用备忘录来记录一些比较重要的或者容易遗忘的信息,与之相关的最常见的应用有许多,比如游戏存档,我们玩游戏的时候肯定有存档功能,旨在下一次登录游戏时可以从上次退出的地方继续游戏,或者对复活点进行存档,如果挂掉了则可以读取复活点的存档信息重新 ......

一、什么是备忘录模式

  备忘录这个词汇大家应该都不陌生,我就经常使用备忘录来记录一些比较重要的或者容易遗忘的信息,与之相关的最常见的应用有许多,比如游戏存档,我们玩游戏的时候肯定有存档功能,旨在下一次登录游戏时可以从上次退出的地方继续游戏,或者对复活点进行存档,如果挂掉了则可以读取复活点的存档信息重新开始。与之相类似的就是数据库的事务回滚,或者重做日志redo log等。

  备忘录模式(memento),在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存着这个状态。这样以后就可将该对象恢复到原先保存的状态。uml结构图如下:

简说设计模式——备忘录模式

  其中,originator是发起人,负责创建一个备忘录memento,用以记录当前时刻它的内部状态,并可使用备忘录恢复内部状态;memento是备忘录,负责存储originator对象的内部状态,并可防止originator以外的其他对象访问备忘录memento;caretaker是管理者,负责保存好备忘录的memento,不能对备忘录的内容进行操作或检查。

  1. 发起人角色

  记录当前时刻的内部状态,并负责创建和恢复备忘录数据,允许访问返回到先前状态所需的所有数据。

 1 public class originator {
 2     
 3     private string state;
 4 
 5     public string getstate() {
 6         return state;
 7     }
 8 
 9     public void setstate(string state) {
10         this.state = state;
11     }
12     
13     public memento createmento() {
14         return (new memento(state));
15     }
16     
17     public void setmemento(memento memento) {
18         state = memento.getstate();
19     }
20     
21     public void show() {
22         system.out.println("state = " + state);
23     }
24     
25 }

  2. 备忘录角色

  负责存储originator发起人对象的内部状态,在需要的时候提供发起人需要的内部状态。

 1 public class memento {
 2     
 3     private string state;
 4     
 5     public memento(string state) {
 6         this.state = state;
 7     }
 8     
 9     public string getstate() {
10         return state;
11     }
12 
13 }

  3. 备忘录管理员角色

  对备忘录进行管理、保存和提供备忘录,只能将备忘录传递给其他角色。

 1 public class caretaker {
 2     
 3     private memento memento;
 4 
 5     public memento getmemento() {
 6         return memento;
 7     }
 8 
 9     public void setmemento(memento memento) {
10         this.memento = memento;
11     }
12     
13 }

  4. client客户端

  下面编写一小段代码测试一下,即先将状态置为on,保存后再将状态置为off,然后通过备忘录管理员角色恢复初始状态。

 1 public class client {
 2     
 3     public static void main(string[] args) {
 4         originator originator = new originator();
 5         originator.setstate("on");    //originator初始状态
 6         originator.show();
 7         
 8         caretaker caretaker = new caretaker();
 9         caretaker.setmemento(originator.createmento());
10         
11         originator.setstate("off");    //originator状态变为off
12         originator.show();
13         
14         originator.setmemento(caretaker.getmemento());    //回复初始状态
15         originator.show();
16     }
17 
18 }

  运行结果如下:

  简说设计模式——备忘录模式

二、备忘录模式的应用

  1. 何时使用

  • 需要记录一个对象的内部状态时,为了允许用户取消不确定或者错误的操作,能够恢复到原先的状态

  2. 方法

  • 通过一个备忘录类专门存储对象状态

  3. 优点

  • 给用户提供了一种可以恢复状态的机制,可以使用能够比较方便地回到某个历史的状态
  • 实现了信息的封装,使得用户不需要关心状态的保存细节

  4. 缺点

  • 消耗资源

  5. 使用场景

  • 需要保存和恢复数据的相关场景
  • 提供一个可回滚的操作,如ctrl+z、浏览器回退按钮、backspace键等
  • 需要监控的副本场景

  6. 应用实例

  • 游戏存档
  • ctrl+z键、浏览器回退键等(撤销/还原)
  • 棋盘类游戏的悔棋
  • 数据库事务的回滚

  7. 注意事项

  • 为了符合迪米特法则,需要有一个管理备忘录的类
  • 不要在频繁建立备份的场景中使用备忘录模式。为了节约内存,可使用原型模式+备忘录模式

三、备忘录模式的实现

  下面以游戏存档为例,看一下如何用备忘录模式实现。uml图如下:

简说设计模式——备忘录模式

  1. 游戏角色

  简单记录了游戏角色的生命力、攻击力、防御力,通过savestate()方法来保存当前状态,通过recoverystate()方法来恢复角色状态。

 1 public class gamerole {
 2     
 3     private int vit;    //生命力
 4     private int atk;    //攻击力
 5     private int def;    //防御力
 6     
 7     public int getvit() {
 8         return vit;
 9     }
10     public void setvit(int vit) {
11         this.vit = vit;
12     }
13     public int getatk() {
14         return atk;
15     }
16     public void setatk(int atk) {
17         this.atk = atk;
18     }
19     public int getdef() {
20         return def;
21     }
22     public void setdef(int def) {
23         this.def = def;
24     }
25     
26     //状态显示
27     public void statedisplay() {
28         system.out.println("角色当前状态:");
29         system.out.println("体力:" + this.vit);
30         system.out.println("攻击力:" + this.atk);
31         system.out.println("防御力: " + this.def);
32         system.out.println("-----------------");
33     }
34     
35     //获得初始状态
36     public void getinitstate() {
37         this.vit = 100;
38         this.atk = 100;
39         this.def = 100;
40     }
41     
42     //战斗后
43     public void fight() {
44         this.vit = 0;
45         this.atk = 0;
46         this.def = 0;
47     }
48     
49     //保存角色状态
50     public rolestatememento savestate() {
51         return (new rolestatememento(vit, atk, def));
52     }
53     
54     //恢复角色状态
55     public void recoverystate(rolestatememento memento) {
56         this.vit = memento.getvit();
57         this.atk = memento.getatk();
58         this.def = memento.getdef();
59     }
60 
61 }

  2. 角色状态存储箱

  备忘录类,用于存储角色状态。

 1 public class rolestatememento {
 2     
 3     private int vit;    //生命力
 4     private int atk;    //攻击力
 5     private int def;    //防御力
 6     
 7     public rolestatememento(int vit, int atk, int def) {
 8         this.vit = vit;
 9         this.atk = atk;
10         this.def = def;
11     }
12 
13     public int getvit() {
14         return vit;
15     }
16 
17     public void setvit(int vit) {
18         this.vit = vit;
19     }
20 
21     public int getatk() {
22         return atk;
23     }
24 
25     public void setatk(int atk) {
26         this.atk = atk;
27     }
28 
29     public int getdef() {
30         return def;
31     }
32 
33     public void setdef(int def) {
34         this.def = def;
35     }
36     
37 }

  3. 角色状态管理者

  备忘录管理者。

 1 public class rolestatecaretaker {
 2     
 3     private rolestatememento memento;
 4 
 5     public rolestatememento getmemento() {
 6         return memento;
 7     }
 8 
 9     public void setmemento(rolestatememento memento) {
10         this.memento = memento;
11     }
12 
13 }

  4. client客户端

  下面编写一个简单的程序测试一下,编写逻辑大致为打boss前存档,打boss失败了,读档。

 1 public class client {
 2     
 3     public static void main(string[] args) {
 4         //打boss前
 5         gamerole gamerole = new gamerole();
 6         gamerole.getinitstate();
 7         gamerole.statedisplay();
 8         
 9         //保存进度
10         rolestatecaretaker caretaker = new rolestatecaretaker();
11         caretaker.setmemento(gamerole.savestate());
12         
13         //打boss失败
14         gamerole.fight();
15         gamerole.statedisplay();
16         
17         //恢复状态
18         gamerole.recoverystate(caretaker.getmemento());
19         gamerole.statedisplay();
20     }
21 
22 }

  运行结果如下:

  简说设计模式——备忘录模式

 

  源码地址:https://gitee.com/adamjiangwh/gof