设计模式之备忘录模式(上)

备忘录模式
1)概述
1.定义

在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,可以在以后将对象恢复到原先保存的状态。

2.作用

备忘录模式提供了一种状态恢复的实现机制,使得用户可以方便地回到一个特定的历史步骤,当新的状态无效或者存在问题时,可以使用暂时存储起来的备忘录将状态复原。

3.结构图
4.角色

Originator(原发器):它是一个普通类,可以创建一个备忘录,并存储它的当前内部状态,也可以使用备忘录来恢复其内部状态,一般将需要保存内部状态的类设计为原发器。

Memento(备忘录):存储原发器的内部状态,根据原发器来决定保存哪些内部状态。

Caretaker(负责人):负责人又称为管理者,它负责保存备忘录,但是不能对备忘录的内容进行操作或检查,在管理者类中可以存储一个或多个备忘录对象,它只负责存储对象,而不能修改对象,也无须知道对象的实现细节。

5.代码实现

原发器类Originator

复制代码
public class Originator {
    private String state;
    public Originator(){}
    
  // 创建一个备忘录对象
    public Memento createMemento() {
    return new Memento(this);
    }
 
  // 根据备忘录对象恢复原发器状态
    public void restoreMemento(Memento m) {
     state = m.state;
    }
 
    public void setState(String state) {
        this.state=state;
    }
 
    public String getState() {
        return this.state;
    }
}

备忘录类Memento

复制代码
//备忘录类,默认可见性,包内可见
class Memento {
    private String state;
 
    public Memento(Originator o) {
    state = o.getState();
    }
 
    public void setState(String state) {
        this.state=state;
    }
 
    public String getState() {
        return this.state;
    }
}
6.Java语言实现备忘录模式

一般将Memento类与Originator类定义在同一个包(package)中实现封装,在Java语言中可使用默认访问标识符来定义Memento类,保证只有Originator类可以对Memento进行访问。

在Memento中保存了Originator的state值,如果Originator中的state值改变之后需撤销,可以通过调用它的restoreMemento()方法进行恢复。

对于负责人类Caretaker,它用于保存备忘录对象,并提供getMemento()方法向客户端返回一个备忘录对象,原发器通过使用这个备忘录对象可以回到某个历史状态,典型的负责人类的实现代码如下:

复制代码
public class Caretaker {
	private Memento memento;
 
	public Memento getMemento() {
		return memento;
	}
 
	public void setMemento(Memento memento) {
		this.memento=memento;
	}
}

在Caretaker类中不应该直接调用Memento中的状态改变方法,它的作用仅仅用于存储备忘录对象。

7.注意

设计备忘录类时需要考虑其封装性,除了Originator类,不允许其他类来调用备忘录类Memento的构造函数与相关方法,如果不考虑封装性,允许其他类调用setState()等方法,将导致在备忘录中保存的历史状态发生改变,通过撤销操作所恢复的状态就不再是真实的历史状态,备忘录模式也就失去了本身的意义。

2)完整解决方案
1.结构图

Chessman充当原发器,ChessmanMemento充当备忘录,MementoCaretaker充当负责人,在MementoCaretaker中定义了一个ChessmanMemento类型的对象,用于存储备忘录。

2.代码实现
复制代码
//象棋棋子类:原发器
@Data
public class Chessman {
	private String label;
	private int x;
	private int y;
 
	public Chessman(String label,int x,int y) {
		this.label = label;
		this.x = x;
		this.y = 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();
	}
}
 
//象棋棋子备忘录类:备忘录
@Data
class ChessmanMemento {
	private String label;
	private int x;
	private int y;
 
	public ChessmanMemento(String label,int x,int y) {
		this.label = label;
		this.x = x;
		this.y = y;
	}	
}
 
//象棋棋子备忘录管理类:负责人
public class MementoCaretaker {
	private ChessmanMemento memento;
 
	public ChessmanMemento getMemento() {
		return memento;
	}
 
	public void setMemento(ChessmanMemento memento) {
		this.memento = memento;
	}
}

客户端类

复制代码
public class Client {
	public static void main(String[] args) {
		MementoCaretaker mc = new MementoCaretaker();
		
		Chessman chess = new Chessman("车",1,1);
		display(chess);
		mc.setMemento(chess.save()); //保存状态		
		
		chess.setY(4);
		display(chess);
		mc.setMemento(chess.save()); //保存状态
		display(chess);
		
		chess.setX(5);
		display(chess);
		
		System.out.println("******悔棋******");	
		//恢复状态
		chess.restore(mc.getMemento()); 
		display(chess);
	}
	
	public static void display(Chessman chess) {
		System.out.println("棋子" + chess.getLabel() + "当前位置为:" + "第" + chess.getX() + "行" + "第" + chess.getY() + "列。");
	}
}
相关推荐
杨充17 小时前
10.可测试性实战设计
设计模式·开源·代码规范
杨充18 小时前
9.重构十二式的实战
设计模式·开源·代码规范
杨充18 小时前
6.设计原则的全景图
设计模式·开源·全栈
杨充18 小时前
2.面向对象的特性
设计模式
杨充18 小时前
7.SOLID原则案例汇
设计模式·开源·全栈
杨充18 小时前
8.反模式与坏味道
设计模式·开源·代码规范
杨充18 小时前
3.接口vs抽象类比较
设计模式
咖啡八杯21 小时前
文法、BNF与AST
java·设计模式·解释器模式·ast·文法
咖啡八杯1 天前
GoF设计模式——解释器模式
java·后端·spring·设计模式