Go和Java实现备忘录模式
下面通过一个保存游戏进度的案例来说明备忘录模式的使用。
1、备忘录模式
备忘录模式保存一个对象的某个状态,以便在适当的时候恢复对象。备忘录模式属于行为型模式。
-
意图:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。
-
主要解决:所谓备忘录模式就是在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个
状态,这样可以在以后将对象恢复到原先保存的状态。
-
何时使用:很多时候我们总是需要记录一个对象的内部状态,这样做的目的就是为了允许用户取消不确定或者
错误的操作,能够恢复到他原先的状态,使得他有"后悔药"可吃。
-
如何解决:通过一个备忘录类专门存储对象状态。
-
关键代码:客户不与备忘录类耦合,与备忘录管理类耦合。
-
应用实例: 1、后悔药。 2、打游戏时的存档。 3、Windows 里的 ctrl + z。 4、IE 中的后退。 5、数据库的事
务管理。
-
优点:1、给用户提供了一种可以恢复状态的机制,可以使用户能够比较方便地回到某个历史的状态。 2、实
现了信息的封装,使得用户不需要关心状态的保存细节。
-
缺点:消耗资源。如果类的成员变量过多,势必会占用比较大的资源,而且每一次保存都会消耗一定的内存。
-
使用场景:1、需要保存/恢复数据的相关状态场景。 2、提供一个可回滚的操作。
-
注意事项:1、为了符合迪米特原则,还要增加一个管理备忘录的类。 2、为了节约内存,可使用原型模式+备
忘录模式。
-
适用性:
必须保存一个对象在某一个时刻的(部分)状态,这样以后需要时它才能恢复到先前的状态。
如果一个用接口来让其它对象直接得到这些状态,将会暴露对象的实现细节并破坏对象的封装性。
2、Go实现备忘录模式
package memento
// ========== 角色状态存储箱RoleStateMemento ==========
// 备忘录存储原发器对象的内部状态
type RoleStateMemento struct {
// 生命力
vit int
// 攻击力
atk int
// 防御力
def int
}
func NewRoleStateMemento(vit, atk, def int) RoleStateMemento {
return RoleStateMemento{
vit: vit,
atk: atk,
def: def,
}
}
package memento
import "fmt"
// ========== 游戏角色GameRole ==========
// 原发器创建一个备忘录,用以记录当前时刻的内部状态,使用备忘录恢复内部状态
type GameRole struct {
// 生命力
vit int
// 攻击力
atk int
// 防御力
def int
}
// 状态显示
func (gameRole *GameRole) StateDisplay() {
fmt.Println("角色当前状态: ")
fmt.Println("体力: ", gameRole.vit)
fmt.Println("攻击力: ", gameRole.atk)
fmt.Println("防御力: ", gameRole.def)
}
// 获得初始状态
func (gameRole *GameRole) GetInitState() {
gameRole.vit = 100
gameRole.atk = 100
gameRole.def = 100
}
// 战斗
func (gameRole *GameRole) Fight() {
gameRole.vit = 0
gameRole.atk = 0
gameRole.def = 0
}
// 保存角色状态
func (gameRole *GameRole) SaveState() RoleStateMemento {
return NewRoleStateMemento(gameRole.vit, gameRole.atk, gameRole.def)
}
// 恢复角色状态
func (gameRole *GameRole) RecoveryState(roleStateMemento RoleStateMemento) {
gameRole.vit = roleStateMemento.vit
gameRole.atk = roleStateMemento.atk
gameRole.def = roleStateMemento.def
}
package memento
// ========== 角色状态管理者RoleStateCaretaker ==========
// 负责保存好备忘录,不能对备忘录的内部进行操作或检查
type RoleStateCaretaker struct {
roleStateMemento RoleStateMemento
}
func (roleStateCaretaker *RoleStateCaretaker) GetRoleStateMemento() RoleStateMemento {
return roleStateCaretaker.roleStateMemento
}
func (roleStateCaretaker *RoleStateCaretaker) SetRoleStateMemento(roleStateMemento RoleStateMemento) {
roleStateCaretaker.roleStateMemento = roleStateMemento
}
package main
import . "proj/memento"
func main() {
gameRole := GameRole{}
gameRole.GetInitState()
gameRole.StateDisplay()
// 保存进度
roleStateCaretaker := RoleStateCaretaker{}
roleStateCaretaker.SetRoleStateMemento(gameRole.SaveState())
// 进行战斗
gameRole.Fight()
gameRole.StateDisplay()
// 恢复之前状态
gameRole.RecoveryState(roleStateCaretaker.GetRoleStateMemento())
gameRole.StateDisplay()
}
# 程序输出
角色当前状态:
体力: 100
攻击力: 100
防御力: 100
角色当前状态:
体力: 0
攻击力: 0
防御力: 0
角色当前状态:
体力: 100
攻击力: 100
防御力: 100
3、Java备忘录模式
package com.memento;
// ========== 角色状态存储箱RoleStateMemento ==========
// 备忘录存储原发器对象的内部状态
public class RoleStateMemento {
// 生命力
private int vit;
// 攻击力
private int atk;
// 防御力
private int def;
public RoleStateMemento(int vit,int atk,int def){
this.vit = vit;
this.atk = atk;
this.def = def;
}
public int getVit() {
return vit;
}
public void setVit(int vit) {
this.vit = vit;
}
public int getAtk() {
return atk;
}
public void setAtk(int atk) {
this.atk = atk;
}
public int getDef() {
return def;
}
public void setDef(int def) {
this.def = def;
}
}
package com.memento;
// ========== 游戏角色GameRole ==========
// 原发器创建一个备忘录,用以记录当前时刻的内部状态,使用备忘录恢复内部状态
public class GameRole {
// 生命力
private int vit;
// 攻击力
private int atk;
// 防御力
private int def;
public int getVit() {
return vit;
}
public void setVit(int vit) {
this.vit = vit;
}
public int getAtk() {
return atk;
}
public void setAtk(int atk) {
this.atk = atk;
}
public int getDef() {
return def;
}
public void setDef(int def) {
this.def = def;
}
// 状态显示
public void stateDisplay(){
System.out.println("角色当前状态: ");
System.out.println("体力: "+this.vit);
System.out.println("攻击力: "+this.atk);
System.out.println("防御力: "+this.def);
}
// 获得初始状态
public void getInitState(){
this.vit = 100;
this.atk = 100;
this.def = 100;
}
// 战斗
public void fight(){
this.vit = 0;
this.atk = 0;
this.def = 0;
}
// 保存角色状态
public RoleStateMemento saveState(){
return new RoleStateMemento(vit,atk,def);
}
// 恢复角色状态
public void recoveryState(RoleStateMemento roleStateMemento){
this.vit = roleStateMemento.getVit();
this.atk = roleStateMemento.getAtk();
this.def = roleStateMemento.getDef();
}
}
package com.memento;
// ========== 角色状态管理者RoleStateCaretaker ==========
// 负责保存好备忘录,不能对备忘录的内部进行操作或检查
public class RoleStateCaretaker {
private RoleStateMemento roleStateMemento;
public RoleStateMemento getRoleStateMemento() {
return roleStateMemento;
}
public void setRoleStateMemento(RoleStateMemento roleStateMemento) {
this.roleStateMemento = roleStateMemento;
}
}
package com.memento;
public class Test {
public static void main(String[] args) {
GameRole gameRole = new GameRole();
gameRole.getInitState();
gameRole.stateDisplay();
// 保存进度
RoleStateCaretaker roleStateCaretaker = new RoleStateCaretaker();
roleStateCaretaker.setRoleStateMemento(gameRole.saveState());
// 进行战斗
gameRole.fight();
gameRole.stateDisplay();
// 恢复之前状态
gameRole.recoveryState(roleStateCaretaker.getRoleStateMemento());
gameRole.stateDisplay();
}
}
# 程序输出
角色当前状态:
体力: 100
攻击力: 100
防御力: 100
角色当前状态:
体力: 0
攻击力: 0
防御力: 0
角色当前状态:
体力: 100
攻击力: 100
防御力: 100