题目分析:备忘录模式的定义是捕获一个对象的内部状态并在该对象之外保存这个内部状态。从这个模式的定义可知我们需要一个类随时对目标对象的保存和创建进行管理,这个类就是Origintor(发起人)类,同时也用它对当前的状态进行管理,以便随时保存。然后需要一个类CareTaker负责保存好备忘录。
UML图:
package com.cmc;
//棋子类,负责记录当前是哪个棋子以及棋子在棋盘上的位置
public class ChessMemento {
private int x;
private int y;//象棋的当前坐标
private int id;//棋子的id
private String label;//棋子名称
public ChessMemento(int x, int y, String label) {
super();
this.x = x;
this.y = y;
this.label = label;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getLabel() {
return label;
}
public void setLabel(String label) {
this.label = label;
}
@Override
public String toString() {
return "棋子"+this.label+"当前位置为("+x+","+y+")";
}
}
package com.cmc;
//发起人类,负责对当前操作的棋子的状态的表现,实现对状态的查看恢复和保存。
public class Originator {
private int x;
private int y;//象棋的当前坐标
private int id;//棋子的id
private String label;//棋子名称
public Originator(int x, int y, String label) {
super();
this.x = x;
this.y = y;
this.label = label;
}
public void setState(int x,int y){
this.x = x;
this.y = y;
}
public ChessMemento CreatMemento(){
return new ChessMemento(x,y,label);
}
public void setMemento(ChessMemento c){
if(c==null)return;
this.x = c.getX();
this.y = c.getY();
this.id = c.getId();
this.label = c.getLabel();
}
public void show(){
System.out.println(CreatMemento());
}
}
package com.cmc;
import java.util.ArrayList;
//状态管理类,对发起人要保存的状态进行记录,支持多步悔棋
public class CareTaker {
private ArrayList<ChessMemento> list = null;
public CareTaker() {
super();
list = new ArrayList<ChessMemento>();
}
public void addMemento(ChessMemento c){
list.add(c);
}
public ChessMemento huiQi(){
if(list.isEmpty()){
System.out.println("无法悔棋!!");
return null;
}else{
int index = list.size();
ChessMemento c = (ChessMemento)list.get(index-1);
list.remove(index-1);
return c;
}
}
}
package com.cmc;
//客户端测试
public class CLient {
public static void main(String[]args){
CareTaker careTaker = new CareTaker();
careTaker.huiQi();
Originator o = new Originator(0,0,"炮");
o.show();
careTaker.addMemento(o.CreatMemento());
o.setState(0, 5);
o.show();
System.out.println("--现在悔棋--");
o.setMemento(careTaker.huiQi());
o.show();
o.setState(6, 0);
o.show();
careTaker.addMemento(o.CreatMemento());
o.setState(6, 9);
o.show();
careTaker.addMemento(o.CreatMemento());
o.setState(4, 9);
o.show();
System.out.println("--现在悔棋--");
o.setMemento(careTaker.huiQi());
o.show();
System.out.println("--现在悔棋--");
o.setMemento(careTaker.huiQi());
o.show();
System.out.println("--现在悔棋--");
o.setMemento(careTaker.huiQi());
o.show();
}
}
输出:
无法悔棋!!
棋子炮当前位置为(0,0)
棋子炮当前位置为(0,5)
--现在悔棋--
棋子炮当前位置为(0,0)
棋子炮当前位置为(6,0)
棋子炮当前位置为(6,9)
棋子炮当前位置为(4,9)
--现在悔棋--
棋子炮当前位置为(6,9)
--现在悔棋--
棋子炮当前位置为(6,0)
--现在悔棋--
无法悔棋!!
备忘录模式优点:
1. 可以保存和恢复内部状态
2. 备忘录对象来封装要保存的状态数据,Caretaker持有备忘录对象,实现职责的分离,松散耦合,易于扩展功能
备忘录模式缺点:
1. Caretaker缓存备忘录对象,有可能会造成内存泄漏
2. 破坏了原发器的封装性
问题:当要保存的状态较多时,Originator 和Memento这两个类需要都把这些状态作为成员变量。造成代码冗余。
解决:把需要保存的状态抽象成一个抽象数据类,让这两个类分别对这个数据类进行扩展。这样既没有造成重新耦合,又解决了代码冗余问题。