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


     在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)防止外界对象破坏一个对象历史状态的封装性,避免将对象历史状态实现细节暴露给外界对象。

  • 相关阅读:
    [CISCN2019 华北赛区 Day1 Web5]CyberPunk
    通用工作站设计方案 :807-ORI-S3R500 -多路PCIe3.0的单CPU通用工作站
    DRF: 序列化器、View、APIView、GenericAPIView、Mixin、ViewSet、ModelViewSet的源码解析
    多表操作(外键)
    HTML5新特性以及主体构成
    k8s入门之pod(四)
    【C++】day6学习成果
    freeradius安装
    算法常见知识点(持续更新)
    Collaborative Filtering for Implicit Feedback Datasets结论公式推导
  • 原文地址:https://blog.csdn.net/qq_25308331/article/details/133871505