文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

设计模式系列—备忘录模式

2024-12-03 17:32

关注

 模式定义

在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,以便以后当需要时能将该对象恢复到原先保存的状态。该模式又叫快照模式。

模版实现如下:

  1. package com.niuh.designpattern.memento.v1; 
  2.  
  3.  
  4. public class MementoPattern { 
  5.     public static void main(String[] args) { 
  6.         Originator or = new Originator(); 
  7.         Caretaker cr = new Caretaker(); 
  8.         or.setState("S0"); 
  9.         System.out.println("初始状态:" + or.getState()); 
  10.         cr.setMemento(or.createMemento()); //保存状态       
  11.         or.setState("S1"); 
  12.         System.out.println("新的状态:" + or.getState()); 
  13.         or.restoreMemento(cr.getMemento()); //恢复状态 
  14.         System.out.println("恢复状态:" + or.getState()); 
  15.     } 
  16.  
  17. //备忘录 
  18. class Memento { 
  19.     private String state; 
  20.  
  21.     public Memento(String state) { 
  22.         this.state = state; 
  23.     } 
  24.  
  25.     public void setState(String state) { 
  26.         this.state = state; 
  27.     } 
  28.  
  29.     public String getState() { 
  30.         return state; 
  31.     } 
  32.  
  33. //发起人 
  34. class Originator { 
  35.     private String state; 
  36.  
  37.     public void setState(String state) { 
  38.         this.state = state; 
  39.     } 
  40.  
  41.     public String getState() { 
  42.         return state; 
  43.     } 
  44.  
  45.     public Memento createMemento() { 
  46.         return new Memento(state); 
  47.     } 
  48.  
  49.     public void restoreMemento(Memento m) { 
  50.         this.setState(m.getState()); 
  51.     } 
  52.  
  53. //管理者 
  54. class Caretaker { 
  55.     private Memento memento; 
  56.  
  57.     public void setMemento(Memento m) { 
  58.         memento = m; 
  59.     } 
  60.  
  61.     public Memento getMemento() { 
  62.         return memento; 
  63.     } 

输出结果如下:

  1. 初始状态:S0 
  2. 新的状态:S1 
  3. 恢复状态:S0 

解决的问题

备忘录模式能记录一个对象的内部状态,当用户后悔时能撤销当前操作,使数据恢复到它原先的状态。

每个人都有犯错误的时候,都希望有种“后悔药”能弥补自己的过失,让自己重新开始,但现实是残酷的。在计算机应用中,客户同样会常常犯错误,能否提供“后悔药”给他们呢?当然是可以的,而且是有必要的。这个功能由“备忘录模式”来实现。

模式组成

 

备忘录模式的核心是设计备忘录类以及用于管理备忘录的管理者类。

实例说明

实例概况

 

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

使用步骤

 

步骤1:定义备忘录角色,用于存储角色状态。

  1. 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.     } 

步骤2:定义发起人角色(当前游戏角色),记录当前游戏角色的生命力、攻击力、防御力。通过saveState()方法来保存当前状态,通过recoveryState()方法来恢复角色状态。

  1. 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.  
  11.     public void setVit(int vit) { 
  12.         this.vit = vit; 
  13.     } 
  14.  
  15.     public int getAtk() { 
  16.         return atk; 
  17.     } 
  18.  
  19.     public void setAtk(int atk) { 
  20.         this.atk = atk; 
  21.     } 
  22.  
  23.     public int getDef() { 
  24.         return def; 
  25.     } 
  26.  
  27.     public void setDef(int def) { 
  28.         this.def = def; 
  29.     } 
  30.  
  31.     //状态显示 
  32.     public void stateDisplay() { 
  33.         System.out.println("角色当前状态:"); 
  34.         System.out.println("体力:" + this.vit); 
  35.         System.out.println("攻击力:" + this.atk); 
  36.         System.out.println("防御力: " + this.def); 
  37.         System.out.println("-----------------"); 
  38.     } 
  39.  
  40.     //获得初始状态 
  41.     public void getInitState() { 
  42.         this.vit = 100; 
  43.         this.atk = 100; 
  44.         this.def = 100; 
  45.     } 
  46.  
  47.     //战斗后 
  48.     public void fight() { 
  49.         this.vit = 0; 
  50.         this.atk = 0; 
  51.         this.def = 0; 
  52.     } 
  53.  
  54.     //保存角色状态 
  55.     public RoleStateMemento saveState() { 
  56.         return (new RoleStateMemento(vit, atk, def)); 
  57.     } 
  58.  
  59.     //恢复角色状态 
  60.     public void recoveryState(RoleStateMemento memento) { 
  61.         this.vit = memento.getVit(); 
  62.         this.atk = memento.getAtk(); 
  63.         this.def = memento.getDef(); 
  64.     } 

步骤3:定义管理者角色,角色状态管理者

  1. 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.     } 

步骤4:测试输出

  1. public class MementoPattern { 
  2.  
  3.     // 逻辑大致为打boss前存档,打boss失败了 
  4.     public static void main(String[] args) { 
  5.         //打boss前 
  6.         GameRole gameRole = new GameRole(); 
  7.         gameRole.getInitState(); 
  8.         gameRole.stateDisplay(); 
  9.  
  10.         //保存进度 
  11.         RoleStateCaretaker caretaker = new RoleStateCaretaker(); 
  12.         caretaker.setMemento(gameRole.saveState()); 
  13.  
  14.         //打boss失败 
  15.         gameRole.fight(); 
  16.         gameRole.stateDisplay(); 
  17.  
  18.         //恢复状态 
  19.         gameRole.recoveryState(caretaker.getMemento()); 
  20.         gameRole.stateDisplay(); 
  21.     } 

输出结果

  1. 角色当前状态: 
  2. 体力:100 
  3. 攻击力:100 
  4. 防御力: 100 
  5. ----------------- 
  6. 角色当前状态: 
  7. 体力:0 
  8. 攻击力:0 
  9. 防御力: 0 
  10. ----------------- 
  11. 角色当前状态: 
  12. 体力:100 
  13. 攻击力:100 
  14. 防御力: 100 

优点

备忘录模式是一种对象行为型模式,其主要优点如下。

缺点

资源消耗大。如果要保存的内部状态信息过多或者特别频繁,将会占用比较大的内存资源。

注意事项

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

应用场景

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

模式的扩展

 

在备忘录模式中,有单状态备份的例子,也有多状态备份的例子。可以结合原型模式混合使用。在备忘录模式中,通过定义“备忘录”来备份“发起人”的信息,而原型模式的 clone() 方法具有自备份功能,所以,如果让发起人实现 Cloneable 接口就有备份自己的功能,这时可以删除备忘录类,其结构如下:

源码中的应用

  1. #Spring 
  2. org.springframework.binding.message.StateManageableMessageContext 

StateManageableMessageContext 部分源码

  1. public interface StateManageableMessageContext extends MessageContext { 
  2.  
  3.     
  4.    public Serializable createMessagesMemento(); 
  5.  
  6.     
  7.    public void restoreMessages(Serializable messagesMemento); 
  8.  
  9.     
  10.    public void setMessageSource(MessageSource messageSource); 

PS:以上代码提交在 Github :

https://github.com/Niuh-Study/niuh-designpatterns.git

来源:今日头条内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯