Java设计模式(二十二)行为型- 备忘录模式 Memento Pattern(史上最全备忘录模式)与使用场景以及优缺点

  1. 备忘录模式 Memento Pattern

备忘录模式又称为快照模式(Snapshot Pattern)或令牌模式(Token Pattern),是指在不破坏封装的前提下,捕获一个对象的内部状态,并在对象之外保存这个状态,这样以后就可将该对象恢复到原先保存的状态。

特征:“后悔药”

备忘录模式的主要角色如下:

  • 发起人(Originator)角色:记录当前时刻的内部状态信息,提供创建备忘录和恢复备忘录数据的功能,实现其他业务功能,它可以访问备忘录里的所有信息。
  • 备忘录(Memento)角色:负责存储发起人的内部状态,在需要的时候提供这些内部状态给发起人。
  • 管理者(Caretaker)角色:对备忘录进行管理,提供保存与获取备忘录的功能,但其不能对备忘录的内容进行访问与修改。

备忘录有两个等效的接口:

  • 窄接口:管理者(Caretaker)对象(和其他发起人对象之外的任何对象)看到的是备忘录的窄接口(narror Interface),这个窄接口只允许他把备忘录对象传给其他的对象。
  • 宽接口:与管理者看到的窄接口相反,发起人对象可以看到一个宽接口(wide Interface),这个宽接口允许它读取所有的数据,以便根据这些数据恢复这个发起人对象的内部状态。

1.1 “ 白箱 ” 备忘录模式

下面就以游戏打怪为简单的例子进行代码实现(下面“黑箱”同这个例子):

备忘录角色对任何对象都提供一个宽接口,备忘录角色的内部所存储的状态就对所有对象公开。

// 游戏角色类
@Data
public class GameRole {
    private Integer vit; // 生命力
    private Integer atk; // 攻击力
    private Integer def; // 防御力
    // 初始化状态
    public void init() {
        this.vit = 100;
        this.atk = 100;
        this.def = 100;
    }
    // 战斗到0
    public void fight() {
        this.vit = 0;
        this.atk = 0;
        this.def = 0;
    }
    // 保存角色状态
    public RoleStateMemento saveState() {
        return new RoleStateMemento(this.vit, this.atk, this.def);
    }
    // 回复角色状态
    public void recoverState(RoleStateMemento roleStateMemento) {
        this.vit = roleStateMemento.getVit();
        this.atk = roleStateMemento.getAtk();
        this.def = roleStateMemento.getDef();
    }
    // 展示状态
    public void showState() {
        System.out.println("角色生命力:" + this.vit);
        System.out.println("角色攻击力:" + this.atk);
        System.out.println("角色防御力:" + this.def);
    }
}
// 游戏状态存储类(备忘录类)
@Data
@AllArgsConstructor
public class RoleStateMemento {
    private Integer vit; // 生命力
    private Integer atk; // 攻击力
    private Integer def; // 防御力
}
// 角色状态管理者类
@Data
public class RoleStateCaretaker {
    private RoleStateMemento roleStateMemento;
}
    // 测试结果
    public static void main(String[] args){
      System.out.println("===========打boss前状态===========");
      GameRole gameRole = new GameRole();
      gameRole.init();
      gameRole.showState();
      // 保存进度
      RoleStateCaretaker roleStateCaretaker = new RoleStateCaretaker();
      roleStateCaretaker.setRoleStateMemento(gameRole.saveState());
      System.out.println("===========打boss后状态===========");
      gameRole.fight();
      gameRole.showState();
      System.out.println("===========恢复状态===========");
      gameRole.recoverState(roleStateCaretaker.getRoleStateMemento());
      gameRole.showState();
      // ===========打boss前状态===========
      // 角色生命力:100
      // 角色攻击力:100
      // 角色防御力:100
      // ===========打boss后状态===========
      // 角色生命力:0
      // 角色攻击力:0
      // 角色防御力:0
      // ===========恢复状态===========
      // 角色生命力:100
      // 角色攻击力:100
      // 角色防御力:100
    }
 

“白箱”备忘录模式是破坏封装性的,但是通过程序员自律,同样可以在一定程度上实现大部分的用意。

1.2 “ 黑箱 ” 备忘录模式

备忘录角色对发起人对象提供了一个宽接口,而为其他对象提供一个窄接口,在Java语言中,实现双重接口的办法就是将备忘录类设计成发起人类的内部成员类。

将RoleStateMemento设为GameRole的内部类,从而将RoleStateMemento对象封装在GameRole 里面;在外面提供一个标识接口Memento给RoleStateCaretaker及其他对象使用。这样GameRole类看到的是RoleStateMemento所有的接口,而RoleStateCaretaker及其他对象看到的仅仅是标识接口Memento所暴露出来的接口,从而维护了封装型。

// 窄接口,标识接口
public interface Memento {
}
// 角色状态管理者类
@Data
public class RoleStateCaretaker {
    private Memento memento;
}
// 游戏角色类
@Data
public class GameRole {
    private Integer vit; // 生命力
    private Integer atk; // 攻击力
    private Integer def; // 防御力
    // 初始化状态
    public void init() {
        this.vit = 100;
        this.atk = 100;
        this.def = 100;
    }
    // 战斗到0
    public void fight() {
        this.vit = 0;
        this.atk = 0;
        this.def = 0;
    }
    // 保存角色状态
    public RoleStateMemento saveState() {
        return new RoleStateMemento(this.vit, this.atk, this.def);
    }
    // 回复角色状态
    public void recoverState(Memento memento) {
        RoleStateMemento roleStateMemento = (RoleStateMemento) memento;
        this.vit = roleStateMemento.getVit();
        this.atk = roleStateMemento.getAtk();
        this.def = roleStateMemento.getDef();
    }
    // 展示状态
    public void showState() {
        System.out.println("角色生命力:" + this.vit);
        System.out.println("角色攻击力:" + this.atk);
        System.out.println("角色防御力:" + this.def);
    }
    // 备忘录内部类
    @Data
    @AllArgsConstructor
    private class RoleStateMemento implements Memento {
        private Integer vit; // 生命力
        private Integer atk; // 攻击力
        private Integer def; // 防御力
    }
}
    // 测试结果
    public static void main(String[] args){
      System.out.println("===========打boss前状态===========");
      GameRole gameRole = new GameRole();
      gameRole.init();
      gameRole.showState();
      // 保存进度
      RoleStateCaretaker roleStateCaretaker = new RoleStateCaretaker();
      roleStateCaretaker.setMemento(gameRole.saveState());
      System.out.println("===========打boss后状态===========");
      gameRole.fight();
      gameRole.showState();
      System.out.println("===========恢复状态===========");
      gameRole.recoverState(roleStateCaretaker.getMemento());
      gameRole.showState();
      // ===========打boss前状态===========
      // 角色生命力:100
      // 角色攻击力:100
      // 角色防御力:100
      // ===========打boss后状态===========
      // 角色生命力:0
      // 角色攻击力:0
      // 角色防御力:0
      // ===========恢复状态===========
      // 角色生命力:100
      // 角色攻击力:100
      // 角色防御力:100
    }

1.3 总结

适用场景

  • 需要保存历史快照的场景。
    -希望在对象之外保存状态,且除了自己其他类对象无法访问状态保存具体内容。

优点:

-简化发起人实体类职责,隔离状态存储与获取,实现了信息的封装,客户端无需关心状态的保存细节。
-提供状态回滚功能。

缺点:

  • 消耗资源:如果需要保存的状态过多时,每一次保存都会消耗很多内存
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
标准备忘录模式Memento Pattern)是一种行为设计模式,它允许在不暴露对象实现细节的情况下保存和恢复对象的内部状态。下面是一个简单的Java代码实现: ```java // 备忘录类 class Memento { private String state; public Memento(String state) { this.state = state; } public String getState() { return state; } } // 原始类 class Originator { private String state; public void setState(String state) { this.state = state; } public String getState() { return state; } public Memento saveStateToMemento() { return new Memento(state); } public void getStateFromMemento(Memento memento) { state = memento.getState(); } } // 管理者类 class CareTaker { private List<Memento> mementoList = new ArrayList<>(); public void add(Memento state) { mementoList.add(state); } public Memento get(int index) { return mementoList.get(index); } } // 测试类 public class MementoPatternDemo { public static void main(String[] args) { Originator originator = new Originator(); CareTaker careTaker = new CareTaker(); originator.setState("State #1"); originator.setState("State #2"); careTaker.add(originator.saveStateToMemento()); originator.setState("State #3"); careTaker.add(originator.saveStateToMemento()); originator.setState("State #4"); System.out.println("Current State: " + originator.getState()); originator.getStateFromMemento(careTaker.get(0)); System.out.println("First saved State: " + originator.getState()); originator.getStateFromMemento(careTaker.get(1)); System.out.println("Second saved State: " + originator.getState()); } } ``` 在上面的例子中,原始类`Originator`保存了一个内部状态`state`,并实现了创建备忘录对象、从备忘录对象恢复状态的方法。备忘录类`Memento`保存了原始类的某个状态。管理者类`CareTaker`负责保存备忘录对象,以便在需要的时候从中取出。测试类`MementoPatternDemo`是一个简单的使用例子,它将原始类的状态进行了多次修改,并保存了多个备忘录对象,最后通过管理者类从备忘录对象中恢复了原始类的状态。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

angle⠀

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值