使用备忘录模式实现Undo和Redo

备忘录模式有三个角色。
1.发起人(Originator)角色:负责创建一个备忘录,用以记录当前时刻自身的内部状态,并可使用备忘录恢复内部状态。实现其他业务功能。
2.备忘录(Memento)角色:负责存储发起人的内部状态。
3.管理者(Caretaker)角色:对备忘录进行管理,提供保存与获取备忘录的功能,但其不能对备忘录的内容进行访问与修改。

/**
 * 发起人角色
 *
 */
public class UnRedoOriginator {
    private String state;

    public UnRedoOriginator() {
    }

    public void setState(String state) {
        this.state = state;
    }

    public String getState() {
        return state;
    }

    public Memento createMemento() {
        return new Memento(state);
    }

    public void restoreMemento(Memento m) {
        if (m != null) {
            this.setState(m.getState());
        } else {
            System.out.println("没有状态可恢复");
        }
    }
}
/**
 * 备忘录
 *
 */
public class Memento {
    private String state;

    public Memento(String state) {
        this.state = state;
    }

    public void setState(String state) {
        this.state = state;
    }

    public String getState() {
        return state;
    }
}
/**
 * 可undo和redo的备忘录管理者
 *
 */
public class UnRedoCaretaker {
    /* 备忘列表 */
    private List<Memento> mementoList;
    /* 备忘列表容量,备忘列表容量 = 最大后退次数 + 1 */
    private int capacity = 3;
    /* 后退索引 */
    private int undoIndex = -2;
    /* 前进索引 */
    private int redoIndex = 0;

    public UnRedoCaretaker() {
        this.mementoList = new LinkedList<>();
    }

    public UnRedoCaretaker(int capacity) {
        this();
        this.capacity = capacity;
    }

    /**
     * 添加备忘
     *
     * @param memento
     */
    public void addMemento(Memento memento) {
        // 添加备忘前,移除当前状态之后的备忘
        for (int i = this.mementoList.size() - 1; i > this.undoIndex + 1; i--) {
            this.mementoList.remove(i);
        }

        if (this.mementoList.size() >= this.capacity) {
            this.mementoList.remove(0);
        }
        this.mementoList.add(memento);

        this.undoIndex = this.mementoList.size() - 2;
        this.redoIndex = this.mementoList.size();
    }

    /**
     * 后退操作
     *
     * @return
     */
    public Memento undo() {
        Memento result = null;

        if (this.undoIndex >= 0 && this.undoIndex < this.mementoList.size() - 1) {
            result = this.mementoList.get(this.undoIndex);

            this.undoIndex--;
            this.redoIndex--;
        }

        return result;
    }

    /**
     * 前进操作
     *
     * @return
     */
    public Memento redo() {
        Memento result = null;
        if (this.redoIndex > 0 && this.redoIndex < this.mementoList.size()) {
            result = this.mementoList.get(this.redoIndex);

            this.redoIndex++;
            this.undoIndex++;
        }

        return result;
    }
}

把发起人角色与备忘录管理者角色聚合在一起,修改发起人角色类。

/**
 * 发起人角色
 *
 */
public class UnRedoOriginator {
    private String state;
    private UnRedoCaretaker caretaker;

    public UnRedoOriginator() {
        this.caretaker = new UnRedoCaretaker(3);
    }

    private void setState(String state) {
        this.state = state;
    }

    public String getState() {
        return state;
    }

    private Memento createMemento() {
        return new Memento(state);
    }

    private void restoreMemento(Memento m) {
        if (m != null) {
            this.setState(m.getState());
        } else {
            System.out.println("没有状态可恢复");
        }
    }

    public void setAndStoreState(String state) {
        this.setState(state);
        caretaker.addMemento(this.createMemento());
    }

    public void undo() {
        this.restoreMemento(caretaker.undo());
    }

    public void redo() {
        this.restoreMemento(caretaker.redo());
    }
}

测试。

/**
 * 测试 undo和redo
 *
 */
public class TestUnRedo {

    public static void main(String[] args) {
        UnRedoOriginator or = new UnRedoOriginator();

        /* 未设置状态前进后退 */
        or.undo();
        or.redo();

        /* 连续添加操作 */
        System.out.println();
        int num = 1;
        operation(or, num++);
        operation(or, num++);
        operation(or, num++);
        operation(or, num++);

        /* 后退次数超过可后退次数 */
        back(or);
        back(or);
        back(or);

        /* 后退时添加新操作,然后再后退 */
        System.out.println();
        operation(or, num++);
        back(or);
        forward(or);
        forward(or);// 前进次数超过可前进次数

        /* 后退时添加新操作,然后redo */
        System.out.println();
        back(or);
        operation(or, num++);
        forward(or);
    }

    private static void operation(UnRedoOriginator or, int name) {
        System.out.println("*******操作*******");
        or.setAndStoreState("操作" + name);
        System.out.println("当前状态:" + or.getState());
    }

    private static void back(UnRedoOriginator or) {
        System.out.println("-------后退-------");
        or.undo();
        System.out.println("当前状态:" + or.getState());
    }

    private static void forward(UnRedoOriginator or) {
        System.out.println("=======前进=======");
        or.redo();
        System.out.println("当前状态:" + or.getState());
    }

}

运行结果如下。

没有状态可恢复
没有状态可恢复

*******操作*******
当前状态:操作1
*******操作*******
当前状态:操作2
*******操作*******
当前状态:操作3
*******操作*******
当前状态:操作4
-------后退-------
当前状态:操作3
-------后退-------
当前状态:操作2
-------后退-------
没有状态可恢复
当前状态:操作2

*******操作*******
当前状态:操作5
-------后退-------
当前状态:操作2
=======前进=======
当前状态:操作5
=======前进=======
没有状态可恢复
当前状态:操作5

-------后退-------
当前状态:操作2
*******操作*******
当前状态:操作6
=======前进=======
没有状态可恢复
当前状态:操作6

原文地址:https://blog.51cto.com/7266799/2444548

时间: 2024-10-05 05:02:43

使用备忘录模式实现Undo和Redo的相关文章

命令模式-实现undo和redo

这次实验主要是实现多次redo和undo,即程序的撤回和恢复,这里只实现加法的撤回和恢复. 程序的撤回和恢复就是由所使用的软件来记录操作步骤,可以将数据恢复到某个操作状态. 撤回这个指令很常见,Windows系统常用的快捷键ctrl+z就可以实现撤回的效果 恢复目前只在word等文档编辑软件见到. 首先说一下命令模式的结构(参考该类图,使用starUML制作): Adder类是加法的计算和返回计算后的结果, AbstrCommand是抽象类,定义三个抽象方法,AddCommand类继承Abstr

设计模式-备忘录模式实现悔棋操作

利用设计模式中的备忘录模式实现多步悔棋的操作 1 import java.util.*; 2 class Chessman { 3 private String label; 4 private int x; 5 private int y; 6 public static int index=-1; 7 public Chessman(String label,int x,int y) { 8 this.label = label; 9 this.x = x; 10 this.y = y; 1

浅析备忘录模式

在应用程序设计过程中,一些具体操作需要能够支持撤销(undo),例如最近在写的一个文件管理系统.文件的一些基本操作如:rename.copy.cut等,需要支持undo.redo操作来提供更好的用户体验.总所周知,undo.redo操作需要两个模式支撑:备忘录模式(memento)保存对象操作数据状态.命令模式(command)封装用户请求.结合起来可以提供良好的撤销.重做操作.命令模式可以参考上面一篇文章点击打开链接.下面主要说说备忘录模式的实现,如有错误,不令赐教. 备忘录模式主要有3个参与

IOS设计模式之四(备忘录模式,命令模式)

本文原文请见:http://www.raywenderlich.com/46988/ios-design-patterns. 由 @krq_tiger(http://weibo.com/xmuzyq)翻译,如果你发现有什么错误,请与我联系谢谢. 备忘录(Memento)模式 备忘录模式快照对象的内部状态并将其保存到外部.换句话说,它将状态保存到某处,过会你可以不破坏封装的情况下恢复对象的状态,也就是说原来对象中的私有数据仍然是私有的. 如何使用备忘录模式 在ViewController.m中增加

用最简单的例子理解备忘录模式(Memento Pattern)

简单来说,备忘录模式就是支持回退操作.假设让一个Notepad支持回退操作,如何实现呢? 首先需要一个备忘录类. public class Memento { private string _msg; public Memento(string msg) { _msg = msg; } public string GetText() { return _msg; } } 以上,○ 构造函数在Nodepad每次记录信息的时候调用,Nodepad所记录的信息最终通过该构造函数赋值给了_msg字段.○

Oracle 中UNDO与REDO的区别详解

    学习设计模式已经有段时间了,初接触设计模式,尽管例子简单.生动,但还是感觉很是抽象.今天又学习了设计模式中的装饰模式,也就是装饰模式让自己对模式略有所懂,装饰模式最大的特点就是把所有需要的功能都按正确的顺序串联起来进行控制.这里需要强调的是"顺序",也就是说这种装饰是建立在一定的顺序之上的,而且这种顺序是由人为控制的:不同于建造者模式,它的顺序是固定不变的. **概念     动态地给一个对象添加一些额外的职责,就增加的功能来说,装饰模式比生成子类更为灵活. **结构图    

第18章 备忘录模式(Memento Pattern)

原文  第18章 备忘录模式(Memento Pattern) 备忘录模式       概述: 备忘录模式(Memento Pattern)又叫做快照模式(Snapshot Pattern)或Token模式,是GoF的23种设计模式之一,属于行为模式. 定义(源于GoF<设计模式>):在不破坏封闭的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态.这样以后就可将该对象恢复到原先保存的状态. 结构图:        代码举例: 1 2 3 4 5 6 7 8 9 10 11 12 13

行为型模式之备忘录模式

概述 备忘录模式提供了一种状态恢复的实现机制,使得用户可以方便地回到一个特定的历史步骤,当新的状态无效或者存在问题时,可以使用暂时存储起来的备忘录将状态复原,当前很多软件都提供了撤销(Undo)操作,其中就使用了备忘录模式. 定义 备忘录模式(Memento Pattern):在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样可以在以后将对象恢复到原先保存的状态.它是一种对象行为型模式,其别名为Token. 实现 原发器 /// <summary> /// 象棋棋子

设计模式(行为型)之备忘录模式(Memento Pattern)

PS一句:最终还是选择CSDN来整理发表这几年的知识点,该文章平行迁移到CSDN.因为CSDN也支持MarkDown语法了,牛逼啊! [工匠若水 http://blog.csdn.net/yanbober] 阅读前一篇<设计模式(行为型)之中介者模式(Mediator Pattern)>http://blog.csdn.net/yanbober/article/details/45533335 概述 备忘录模式提供了一种状态恢复的实现机制,使得用户可以方便地回到一个特定的历史步骤,当新的状态无