1.题目分析

  • 首先需要一个实体类来代表一枚象棋的基本信息,包含象棋的名字/当前坐标
  • 其次需要一个备忘录类来保存象棋的信息,这个类应当含有象棋类的要保存的字段,并且该类对外封闭
  • 由于备忘录类是对外封闭的,所以应当由一个备忘录管理者类,来负责创建和恢复象棋的备忘录
  • 客户端不与备忘录类耦合,而是借用备忘录管理类来管理备忘录

2.UML图

2.代码

  • 象棋实体类
/** * 需要备忘的象棋信息 */
public class Chessman {
    /** * 象棋的基本信息 名字及坐标 */
    private String name;
    private int x;
    private int y;


    /** * 备忘当前象棋的状态 * * @return */
    public ChessmanMemento CreateMemento() {
        return new ChessmanMemento(name, x, y);
    }

    /** * 使用备忘录恢复象棋状态 * * @param chessmanMemento */
    public void setMemento(ChessmanMemento chessmanMemento) {
        this.name = chessmanMemento.getName();
        this.x = chessmanMemento.getX();
        this.y = chessmanMemento.getY();
    }


    public Chessman() {
    }

    public Chessman(String name, int x, int y) {
        this.name = name;
        this.x = x;
        this.y = y;
    }

	//此处省略Get/Set方法
    @Override
    public String toString() {
        return "Chessman{" +
                "name='" + name + '\'' +
                ", x=" + x +
                ", y=" + y +
                '}';
    }
}

  • 象棋备忘录 用于保存象棋的状态信息
/** * 备忘录 用于保存象棋的状态信息 */
public class ChessmanMemento {
    /** * 备忘象棋的基本信息 */
    private String name;
    private int x;
    private int y;

    public ChessmanMemento(String name, int x, int y) {
        this.name = name;
        this.x = x;
        this.y = y;
    }
	//此处省略Get/Set方法
}

  • 备忘录负责人 管理备忘录 隐藏备忘录内部实现
/** * 备忘录负责人 管理备忘录 隐藏备忘录内部实现 */
public class MementoCaretaker {
    private ChessmanMemento chessmanMemento;

    public ChessmanMemento getChessmanMemento() {
        return chessmanMemento;
    }

    public void setChessmanMemento(ChessmanMemento chessmanMemento) {
        this.chessmanMemento = chessmanMemento;
    }
}

  • 象棋悔棋备忘录测试类
/** * 象棋悔棋备忘录测试类 */
public class Main {
    public static void main(String[] args) {
        //象棋初始状态
        Chessman chessman = new Chessman("马", 1, 1);
        System.out.println("象棋初始状态-->" + chessman);

        //保存象棋当前的状态到备忘录
        MementoCaretaker mementoCaretaker = new MementoCaretaker();
        mementoCaretaker.setChessmanMemento(chessman.CreateMemento());

        //修改了象棋的状态
        chessman.setX(666);
        chessman.setY(666);
        System.out.println("象棋修改状态-->" + chessman);


        //此时想要悔棋 可以用备忘录里的数据恢复
        chessman.setMemento(mementoCaretaker.getChessmanMemento());
        System.out.println("象棋恢复状态-->" + chessman);

    }
}

  • 运行结果

3.总结:

1. 该模式的优缺点,特别从开闭原则论述
  • 优点:利用备忘录管理者类,保持了象棋的封闭性,没有破坏其封装。保存了象棋的内部状态,以便在需要的时候恢复状态
  • 缺点:如果类的信息太多,会十分消耗资源
2. 编程中遇到的问题及解决方法:
  • 该模式在不同的场景下有改进的几个方面,比如:备忘录管理者类,其字段备忘录可以改为一个Map类型的,key为唯一的字段属性,value为保存的备忘录对象,这样就可以根据Key来恢复任意一个状态,Github的版本控制就是这个原理,每一个版本都有对应的一个哈希串,可以回退到任意一个版本。
  • 可以结合原型模式+备忘录来处理相应的需求,以减少资源的消耗