备忘录模式
备忘录模式又称为快照模式或令牌模式,属于行为型模式。
它是指在不破坏封装的前提下,捕获一个对象的内部状态,并在对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态。简而言之:允许在不暴露对象实现细节的情况下保存和恢复对象之前的状态。
它提供一种类似“后悔药”的机制,通过存储系统各个历史状态的快照,使得可以在任一时刻将系统回滚到某一个历史状态。
应用场景
1.需要保存历史快照的场景
2.希望在对象之外保存状态,且除了自己其他类对象无法访问状态保存具体内容
应用场景举例:代码版本控制,游戏存档功能,数据库的事务管理等
假如有一款编辑器应用程序,程序在执行任何操作前记录所有的对象状态, 并将其保存下来。 当用户此后需要撤销某个操作时, 程序将从历史记录中获取最近的快照, 然后使用它来恢复所有对象的状态。
优缺点
优点:
1.简化发起人实体类Originator职责,隔离状态存储与获取,实现了信息的封装,客户端无需关心状态的保存细节
2.提供状态回滚功能:给用户提供了一种可以恢复状态的机制,可以使用户能够比较方便地回到某个历史的状态。
缺点:
1.消耗资源:如果需要保存的状态过多时,每一次保存都会消耗很多内存。
主要角色
备忘录模式主要包含三种角色:
1.发起人角色(Originator)
负责创建一个备忘录,记录自身需要保存的状态;具备状态回滚功能。
2.备忘录角色(Memento)
用于存储Originator的内部状态,且可以防止Originator以外的对象进行访问。
3.备忘录管理员角色(Caretaker)
负责存储,提供管理备忘录(Memento),无法对备忘录内容进行操作和访问。
备忘录模式本质是从发起人实体类(Originator)隔离存储功能,降低实体类的职责。同时由于存储信息(Memento)独立,且存储信息的实体交由管理类(Caretaker)管理,则可以通过为管理类扩展额外的功能对存储信息进行扩展操作。
备忘录模式的基本使用
创建发备忘录角色
@Data
public class Memento {
private String state;
public Memento(String state){
this.state = state;
}
}
创建发起人角色
@Data
public class Originator {
/**
* 内部状态
*/
private String state;
/**
* 创建一个备忘录
*
* @return
*/
public Memento createMemento() {
return new Memento(this.state);
}
/**
* 从备忘录恢复
*
* @param memento
*/
public void restoreMemento(Memento memento) {
this.setState(memento.getState());
}
}
创建备忘录管理员角色
public class Caretaker {
private Memento memento;
public Memento getMemento() {
return this.memento;
}
public void storeMemento(Memento memento) {
this.memento = memento;
}
}
客户端执行
public static void main(String[] args) {
// 创建发起人角色
Originator originator = new Originator();
// 创建备忘录管理员
Caretaker caretaker = new Caretaker();
// 设置存储状态
originator.setState("A");
// 存储发起人创建的备忘录
caretaker.storeMemento(originator.createMemento());
System.out.println("设置存储状态:" + originator.getState());
// 设置存储状态
originator.setState("B");
System.out.println("更新存储状态:" + originator.getState());
// 备忘录进行回滚
originator.restoreMemento(caretaker.getMemento());
System.out.println("回滚到设置的状态:" + originator.getState());
}
设置存储状态:A
更新存储状态:B
回滚到设置的状态:A
使用备忘录模式实现代码版本控制
创建发备忘录角色
@Data
@ToString
public class CodeMemento {
/**
* 提交内容
*/
private String content;
/**
* 提交备注
*/
private String remark;
public CodeMemento(String content, String remark) {
this.content = content;
this.remark = remark;
}
}
创建发起人角色
@Data
@ToString
public class GitOriginator {
/**
* 提交内容
*/
private String content;
/**
* 提交备注
*/
private String remark;
public GitOriginator(String content, String remark) {
this.content = content;
this.remark = remark;
}
/**
* 提交代码
*
* @return
*/
public CodeMemento saveToMemento() {
CodeMemento codeMemento = new CodeMemento(this.content, this.remark);
return codeMemento;
}
/**
* 恢复代码
*
* @param codeMemento
*/
public void undoFromMemento(CodeMemento codeMemento) {
this.content = codeMemento.getContent();
this.remark = codeMemento.getRemark();
}
}
创建备忘录管理员角色
public class GitCaretaker {
/**
* 使用栈来存储备忘录,最新的备忘录排在栈顶
*/
private final Stack<CodeMemento> STACK = new Stack<CodeMemento>();
public CodeMemento getMemento(){
// 移除栈顶的备忘录
CodeMemento codeMemento = STACK.pop();
return codeMemento;
}
public void addMemento(CodeMemento codeMemento){
// 将备忘录压入栈顶
STACK.push(codeMemento);
}
}
客户端执行
public static void main(String[] args) {
System.out.println("--------------------第一次创建代码--------------------------------");
// 创建一个备忘录管理者
GitCaretaker gitCaretaker = new GitCaretaker();
// 创建一个备忘录发起人
GitOriginator gitOriginator = new GitOriginator("write code 1", "第一次提交代码备注");
// 创建一个备忘录
CodeMemento codeMemento = gitOriginator.saveToMemento();
// 将备忘录压入栈顶
gitCaretaker.addMemento(codeMemento);
System.out.println("第一次提交代码完成。代码:" + gitOriginator.getContent() + " 备注:" + gitOriginator.getRemark());
System.out.println("--------------------第二次修改代码--------------------------------");
gitOriginator.setContent("write code 2");
gitOriginator.setRemark("第二次提交代码备注");
codeMemento = gitOriginator.saveToMemento();
gitCaretaker.addMemento(codeMemento);
System.out.println("第二次提交代码完成。代码:" + gitOriginator.getContent() + " 备注:" + gitOriginator.getRemark());
System.out.println("--------------------第三次修改代码--------------------------------");
gitOriginator.setContent("write code 3");
System.out.println("第三次修改代码。代码:" + gitOriginator.getContent());
System.out.println("--------------------在第三次修改代码基础上回退到第二次提交--------------------------------");
codeMemento = gitCaretaker.getMemento();
gitOriginator.undoFromMemento(codeMemento);
System.out.println("回退到第二次提交完成。代码:" + gitOriginator.getContent() + " 备注:" + gitOriginator.getRemark());
System.out.println("--------------------在第二次修改代码基础上回退到第一次提交--------------------------------");
codeMemento = gitCaretaker.getMemento();
gitOriginator.undoFromMemento(codeMemento);
System.out.println("回退到第一次提交完成。代码:" + gitOriginator.getContent() + " 备注:" + gitOriginator.getRemark());
}
--------------------第一次创建代码--------------------------------
第一次提交代码完成。代码:write code 1 备注:第一次提交代码备注
--------------------第二次修改代码--------------------------------
第二次提交代码完成。代码:write code 2 备注:第二次提交代码备注
--------------------第三次修改代码--------------------------------
第三次修改代码。代码:write code 3
--------------------在第三次修改代码基础上回退到第二次提交--------------------------------
回退到第二次提交完成。代码:write code 2 备注:第二次提交代码备注
--------------------在第二次修改代码基础上回退到第一次提交--------------------------------
回退到第一次提交完成。代码:write code 1 备注:第一次提交代码备注
标签:gitOriginator,代码,模式,备忘录,提交,设计模式,public,codeMemento
From: https://blog.51cto.com/chencoding/5717460