设计模式之备忘录模式笔记

说明

记录下学习设计模式-备忘录模式的写法。JDK使用版本为1.8版本。

Memento(备忘录)

意图:在不破坏封装性的前提下捕获一个对象的内部状态,并在对象之外保存这个状态。这样以后就可以将对象恢复到原先保存的状态。
结构:
在这里插入图片描述

其中:

  • Memento(备忘录)存储原发器对象的内部状态,原发器根据需要决定备忘录存储原发器的哪些内部状态:防止原发器以外的其他对象访问备忘录。
  • Originator(原发器)创建一个备忘录,用于记录当前时刻它的内部状态;使用备忘录恢复内部状态。
  • Caretaker(管理者)负责保存好备忘录;不能对备忘录的内容进行操作或检查。

适用性:

  • 需要保存与恢复数据的场景,如玩游戏时的中间结果的存档功能。
  • 需要提供一个可回滚操作的场景,如 word记事本、Photoshop,idea等软件在编辑时按 Ctrl+ 组合键,还有数据库中事务操作。

目录

在这里插入图片描述

白箱备忘录模式

备忘录模式示例类图

在这里插入图片描述
在这里插入图片描述

以该UML类图实现白箱备忘录模式示例。

游戏角色类

package com.example.deesign_patterns.memento.white_box;

//游戏角色类(属于发起人角色)
public class GameRole {
    
    

    private int vit;//生命力
    private int atk;//攻击力
    private int def;//防御力

    //初始化内部状态
    public void initState(){
    
    
        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 recoverState(RoleStateMemento roleStateMemento){
    
    
        //将备忘录对象中存储的状态赋值给当前对象的成员
        this.vit=roleStateMemento.getVit();
        this.atk=roleStateMemento.getAtk();
        this.def=roleStateMemento.getDef();
    }

    //展示状态功能
    public void stateDisplay(){
    
    
        System.out.println("角色生命力:"+vit);
        System.out.println("角色攻击力:"+atk);
        System.out.println("角色防御力:"+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.example.deesign_patterns.memento.white_box;

//备忘录角色类
public class RoleStateMemento {
    
    

    private int vit;//生命力
    private int atk;//攻击力
    private int def;//防御力

    public RoleStateMemento() {
    
    
    }

    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.example.deesign_patterns.memento.white_box;

//备忘录对象管理对象
public class RoleStateCaretaker {
    
    

    //声明RoleStateMemento类型的变量
    private RoleStateMemento roleStateMemento;

    public RoleStateMemento getRoleStateMemento() {
    
    
        return roleStateMemento;
    }

    public void setRoleStateMemento(RoleStateMemento roleStateMemento) {
    
    
        this.roleStateMemento = roleStateMemento;
    }
}

测试类

package com.example.deesign_patterns.memento.white_box;

//测试类
public class Client {
    
    

    public static void main(String[] args) {
    
    
        System.out.println("-----------大战boos前-------------");
        //创建游戏角色对象
        GameRole gameRole=new GameRole();
        gameRole.initState();
        gameRole.stateDisplay();
        //将该游戏角色内部状态进行备份
        //创建管理者对象
        RoleStateCaretaker roleStateCaretaker=new RoleStateCaretaker();
        roleStateCaretaker.setRoleStateMemento(gameRole.saveState());

        System.out.println("-----------大战boos后-------------");
        //损耗严重
        gameRole.fight();
        gameRole.stateDisplay();

        System.out.println("-----------恢复之前的状态-------------");
        gameRole.recoverState(roleStateCaretaker.getRoleStateMemento());
        gameRole.stateDisplay();
    }
}

在这里插入图片描述

黑箱备忘录模式

备忘录模式示例类图

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

将 RolestateMemento 设为 GameRole 的内部类,从而将 RoleStateMemento 对象封装在 Gamerole 里面:在外面提供-个标识接口 Memento 给 Rolestatecaretaker 及其对象使用。这样Gamerole 类看到的是 RoleStateMemento 所有的接口,而及其他对象看到的仅仅是标识接口 Memento 所暴露出来的接口,从而维护了封装型。类图如下:
在这里插入图片描述

以该UML类图实现黑箱备忘录模式示例。

备忘录接口

package com.example.deesign_patterns.memento.black_box;

//备忘录接口,对外提供窄接口
public interface Memento {
    
    
}

游戏角色类

package com.example.deesign_patterns.memento.black_box;

//游戏角色类(属于发起人角色)
public class GameRole {
    
    

    private int vit;//生命力
    private int atk;//攻击力
    private int def;//防御力

    //初始化内部状态
    public void initState(){
    
    
        this.vit=100;
        this.atk=100;
        this.def=100;
    }

    //战斗方法
    public void fight(){
    
    
        this.vit=0;
        this.atk=0;
        this.def=0;
    }

    //保存角色状态功能
    public Memento saveState(){
    
    
        return new RoleStateMemento(vit,atk,def);
    }

    //恢复角色状态
    public void recoverState(Memento memento){
    
    
        RoleStateMemento roleStateMemento= (RoleStateMemento) memento;
        //将备忘录对象中存储的状态赋值给当前对象的成员
        this.vit=roleStateMemento.getVit();
        this.atk=roleStateMemento.getAtk();
        this.def=roleStateMemento.getDef();
    }

    //展示状态功能
    public void stateDisplay(){
    
    
        System.out.println("角色生命力:"+vit);
        System.out.println("角色攻击力:"+atk);
        System.out.println("角色防御力:"+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;
    }

    //声明一个内部类
    private class RoleStateMemento implements Memento{
    
    
        private int vit;//生命力
        private int atk;//攻击力
        private int def;//防御力

        public RoleStateMemento() {
    
    
        }

        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.example.deesign_patterns.memento.black_box;


//备忘录对象管理对象
public class RoleStateCaretaker {
    
    

    //声明Memento类型的变量
    private Memento memento;

    public Memento getMemento() {
    
    
        return memento;
    }

    public void setMemento(Memento memento) {
    
    
        this.memento = memento;
    }
}

测试类

package com.example.deesign_patterns.memento.black_box;

//测试类
public class Client {
    
    

    public static void main(String[] args) {
    
    
        System.out.println("-----------大战boos前-------------");
        //创建游戏角色对象
        GameRole gameRole=new GameRole();
        gameRole.initState();
        gameRole.stateDisplay();
        //将该游戏角色内部状态进行备份
        //创建管理者对象
        RoleStateCaretaker roleStateCaretaker=new RoleStateCaretaker();
        roleStateCaretaker.setMemento(gameRole.saveState());

        System.out.println("-----------大战boos后-------------");
        //损耗严重
        gameRole.fight();
        gameRole.stateDisplay();

        System.out.println("-----------恢复之前的状态-------------");
        gameRole.recoverState(roleStateCaretaker.getMemento());
        gameRole.stateDisplay();
    }
}

在这里插入图片描述

好处:

  • 提供了一种可以恢复状态的机制。当用户需要时能够比较方便地将数据恢复到某个历史的状态。
  • 实现了内部状态的封装。除了创建它的发起人之外,其他对象都不能够访问这些状态信息。
  • 简化了发起人类。发起人不需要管理和保存其内部状态的各个备份,所有状态信息都保存在备忘录中,并由管理者进行管理,这符合单职责原则。

缺点:

  • 资源消耗大。如果要保存的内部状态信息过多或者特别频繁,将会占用比较大的内存资源。

猜你喜欢

转载自blog.csdn.net/weixin_48040732/article/details/131371376