• 备忘录模式-撤销功能的实现


     在idea写代码的过程中,会经常用到一个快捷键——“crtl + z”,即撤销功能。“备忘录模式”则为撤销功能提供了一个设计方案。

    1 备忘录模式

    备忘录模式提供一种状态恢复机制。在不破坏封装的前提下,捕获对象内部状态并在该对象之外保存这个状态。可以在以后将对象恢复到原先保存的状态。

    图 备忘录UML

    Originator:原发器,一个需要保存内部状态的普通类,可以创建一个备忘录,也可通过备忘录来恢复其在某个时候的状态。

    Memento:备忘录,存储原发器的内部状态。除了原发器本身及管理者类外,备忘录不能直接供其他类使用。

    CareTaker:管理者,负责保存备忘录,但不能对备忘录内容进行操作或检查,无须知道备忘录的细节。

    1. @Data
    2. public class IdeaCodeOriginator {
    3. private String code;
    4. private Integer position;
    5. public IdeaCodeOriginator(String code, Integer position) {
    6. this.code = code;
    7. this.position = position;
    8. }
    9. public void restoreMemento(IdeaCodeMemento memento) {
    10. this.code = memento.getCode();
    11. this.position = memento.getPosition();
    12. }
    13. public IdeaCodeMemento createMemento() {
    14. return new IdeaCodeMemento(code,position);
    15. }
    16. }
    17. @Data
    18. public class IdeaCodeMemento {
    19. private String code;
    20. private Integer position;
    21. public IdeaCodeMemento(String code, Integer position) {
    22. this.code = code;
    23. this.position = position;
    24. }
    25. }
    26. public class CareTaker {
    27. private final Stack<IdeaCodeMemento> mementoStack = new Stack<>();
    28. public IdeaCodeMemento getMemento(int num) {
    29. IdeaCodeMemento memento = null;
    30. while (num-- > 0 && !mementoStack.isEmpty()) {
    31. memento = mementoStack.pop();
    32. }
    33. return mementoStack.isEmpty() ? memento : mementoStack.pop();
    34. }
    35. public void saveMemento(IdeaCodeMemento memento) {
    36. mementoStack.push(memento);
    37. }
    38. }
    39. public class IdeaCodeEditor {
    40. public static void main(String[] args) {
    41. CareTaker careTaker = new CareTaker();
    42. IdeaCodeOriginator originator1 = new IdeaCodeOriginator("hello", 1);
    43. careTaker.saveMemento(originator1.createMemento());
    44. IdeaCodeOriginator originator2 = new IdeaCodeOriginator("word", 2);
    45. careTaker.saveMemento(originator2.createMemento());
    46. IdeaCodeOriginator originator3 = new IdeaCodeOriginator("and", 3);
    47. careTaker.saveMemento(originator3.createMemento());
    48. IdeaCodeOriginator originator4 = new IdeaCodeOriginator("java", 4);
    49. careTaker.saveMemento(originator4.createMemento());
    50. //撤回到2步前
    51. originator4.restoreMemento(careTaker.getMemento(2));
    52. System.out.println(originator4); // IdeaCodeOriginator(code=word, position=2)
    53. }
    54. }

    1.1 优化

    1)要避免其他类操作或者检查备忘录的内容。

    2)备忘录管理者应该具有通用性。

    1. public interface Memento {
    2. }
    3. @Data
    4. public class IdeaCodeOriginator {
    5. private String code;
    6. private Integer position;
    7. public IdeaCodeOriginator(String code, Integer position) {
    8. this.code = code;
    9. this.position = position;
    10. }
    11. @Data
    12. private static class InnerMemento implements Memento {
    13. private String code;
    14. private Integer position;
    15. public InnerMemento(String code, Integer position) {
    16. this.code = code;
    17. this.position = position;
    18. }
    19. }
    20. public Memento createMemento() {
    21. return new InnerMemento(code,position);
    22. }
    23. public void restoreMemento(Memento memento) throws Exception {
    24. if (memento instanceof InnerMemento) {
    25. InnerMemento innerMemento = (InnerMemento) memento;
    26. this.code = innerMemento.getCode();
    27. this.position = innerMemento.position;
    28. } else {
    29. throw new Exception("类型错误");
    30. }
    31. }
    32. }
    33. public class CareTaker<T> {
    34. Stack<T> stack = new Stack<>();
    35. public T getMemento(int num) {
    36. T memento = null;
    37. while (num-- > 0 && !stack.isEmpty()) {
    38. memento = stack.pop();
    39. }
    40. return stack.isEmpty() ? memento : stack.pop();
    41. }
    42. public void saveMemento(T memento) {
    43. stack.push(memento);
    44. }
    45. }
    46. public class IdeaCodeEditor2 {
    47. public static void main(String[] args) throws Exception {
    48. CareTaker<Memento> objectCareTaker = new CareTaker<>();
    49. IdeaCodeOriginator originator1 = new IdeaCodeOriginator("hello", 1);
    50. objectCareTaker.saveMemento(originator1.createMemento());
    51. IdeaCodeOriginator originator2 = new IdeaCodeOriginator("word", 2);
    52. objectCareTaker.saveMemento(originator2.createMemento());
    53. IdeaCodeOriginator originator3 = new IdeaCodeOriginator("and", 3);
    54. objectCareTaker.saveMemento(originator3.createMemento());
    55. IdeaCodeOriginator originator4 = new IdeaCodeOriginator("java", 4);
    56. objectCareTaker.saveMemento(originator4.createMemento());
    57. originator4.restoreMemento(objectCareTaker.getMemento(3)); // IdeaCodeOriginator(code=hello, position=1)
    58. System.out.println(originator4);
    59. }
    60. }

    2 优缺点

    如果需要为软件提供撤销功能,备忘录模式无疑是一种很好的解决方案。

    优点:1)它提供了一种状态恢复的实现机制,使得用户可以方便地回到一个特定的历史步骤;

    缺点:1)资源消耗过大。如果要保存的原发器类的成员变量太多,就不可避免地占用大量的储存空间。每保存一次对象状态都需要消耗一定的系统资源。

    3 适用场景

    1)保存一个对象在某时刻的全部或部分状态,实现撤销操作。

    2)防止外界对象破坏一个对象历史状态的封装性,避免将对象历史状态实现细节暴露给外界对象。

  • 相关阅读:
    【EasyRL学习笔记】第五章 Proximal Policy Optimization 近端策略优化算法
    web网页设计期末课程大作业:美食餐饮文化主题网站设计——美食汇5页HTML+CSS+JavaScript
    【毕业季】研究生の毕业总结
    第一篇、了解多线程
    为什么说Redis是单线程的以及Redis为什么这么快!
    【微信小程序怎么开店铺】微信小程序店铺怎么制作?
    Imu_PreIntegrate_07 Vecility bias update 零偏更新后速度预积分量对零偏的偏导
    堆 与 堆排序
    请编写一个函数void fun(char*ss),其功能是:将字符串ss中所有下标为奇数位置上的字母转换为大写(若该位置上不是字母,则不转换)。
    内网安全--小结
  • 原文地址:https://blog.csdn.net/qq_25308331/article/details/133871505