我想学会设计模式之备忘录模式

227 阅读2分钟

我想学会设计模式之备忘录模式


这是我参与8月更文挑战的第8天,活动详情查看:8月更文挑战


备忘录模式:属于行为模式,保存某个状态,并且在需要的时候直接获取,而不是重复计算


什么是备忘录模式?

备忘录模式:属于行为模式,保存某个状态,并且在需要的时候直接获取,而不是重复计算

注意:备忘录模式实现,不能破坏原始封装。也就是说,能拿到内部状态,将其保存在外部。


优缺点

优点
  • 它提供了一种状态恢复的实现机制,使得用户可以方便地回到一个特定的历史步骤,当新的状态无效或者存在问题时,可以使用暂时存储起来的备忘录将状态复原。
  • 当发起人角色的状态改变的时候,有可能这个状态无效,这时候就可以使用暂时存储起来的备忘录将状态复原。
缺点
  • 如果发起人角色的状态需要完整地存储到备忘录对象中,那么在资源消耗上面备忘录对象会很昂贵。
  • 资源消耗过大,如果需要保存的原发器类的成员变量太多,就不可避免需要占用大量的存储空间,每保存一次对象的状态都需要消耗一定的系统资源。

应用场景

最典型的例子是“斐波那契数列”递归实现。

不借助备忘录模式,数据一大,就容易爆栈;借助备忘录,算法的时间复杂度可以降低到O(n)。除此之外,数据的缓存等也是常见应用场景。


实现

场景:下棋例子,可以下棋,悔棋,撤销悔棋等

@Data
@AllArgsConstructor
class Chessman {
    private String label;
    private int x;
    private int y;

    //保存状态
    public ChessmanMemento save() {
        return new ChessmanMemento(this.label, this.x, this.y);
    }

    //恢复状态
    public void restore(ChessmanMemento memento) {
        this.label = memento.getLabel();
        this.x = memento.getX();
        this.y = memento.getY();
    }

    public void show() {
        System.out.println(String.format("棋子<%s>:当前位置为:<%d, %d>", this.getLabel(), this.getX(), this.getY()));
    }
}

class MementoCaretaker {
    //定义一个集合来存储备忘录
    private ArrayList mementolist = new ArrayList();

    public ChessmanMemento getMemento(int i) {
        return (ChessmanMemento) mementolist.get(i);
    }

    public void addMemento(ChessmanMemento memento) {
        mementolist.add(memento);
    }
}
@Data
@AllArgsConstructor
class ChessmanMemento {
    private String label;
    private int x;
    private int y;
}
class Client {
    private static int index = -1;
    private static MementoCaretaker mc = new MementoCaretaker();

    public static void main(String args[]) {
        Chessman chess = new Chessman("车", 1, 1);
        play(chess);
        chess.setY(4);
        play(chess);
        chess.setX(5);
        play(chess);
        undo(chess, index);
        undo(chess, index);
        redo(chess, index);
        redo(chess, index);
    }

    //下棋,同时保存备忘录
    public static void play(Chessman chess) {
        mc.addMemento(chess.save());
        index++;
        chess.show();
    }

    //悔棋,撤销到上一个备忘录
    public static void undo(Chessman chess, int i) {
        System.out.println("******悔棋******");
        index--;
        chess.restore(mc.getMemento(i - 1));
        chess.show();
    }

    //撤销悔棋,恢复到下一个备忘录
    public static void redo(Chessman chess, int i) {
        System.out.println("******撤销悔棋******");
        index++;
        chess.restore(mc.getMemento(i + 1));
        chess.show();
    }
}