设计模式之备忘录模式

本文介绍了备忘录模式的概念,以及通过白盒、黑盒和自我实现三种方式进行详细阐述。推荐使用黑盒模式,因为其能确保备忘录信息的安全性。备忘录模式用于备份对象状态,便于恢复到先前状态,而自我实现模式即原型模式,虽可避免但可能违反单一职责原则。文章还提供了类图和代码实例以帮助理解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

从头再来(备忘录)

  • 概念
  • 备忘录模式实现的三种方式
  • 类图
  • 代码实例

概念

备份对象状态,以便恢复到上一个状态。 通俗来说就是在对象(Originator发起人)执行某个动作之前先将状态(属性值)拷贝一份到一个备忘录(Memento备忘录)对象中,并且由一个管理者(Caretaker管理者)保管。 然后对象执行动作,执行完后又想要回到执行动作之前的状态,那么就是将被备忘录对象属性值重新再赋值给该对象。 如果想要永久持久化则数据放到磁盘中,而非内存中。

备忘录模式实现的三种方式

白盒模式

也就是说在管理者可以访问保存的备忘录的方法进而可以查看其属性值,并且同样可以修改其属性,这是不安全且不合理,按正常逻辑管理者只对备忘录进行保存,而发起类可以对备忘录中的属性进行访问。

黑盒模式

和上面白盒模式不同就是,备忘录中的信息对于管理者来说完全屏蔽,就相当于一个黑盒子样什么也看不到,然而为了保证备忘录仅仅存放的发起人相关的状态,所以把备忘录类作为发起人类的私有内部类。下面类图和代码就是黑盒模式并且也推荐使用其模式。

自我实现模式

这个就是我们之前介绍的原型模式,也就是发起人实现其Cloneable接口,并且生成一个新的对象,其中如果是引用类型要考虑是否需要深度克隆,具体详情可以查看之前讲解的原型模式

这样就可以不需要使用备忘录类了,这种模式不推荐使用,因为我们备份对象的状态可以就是几个属性值,而使用克隆方式可以仅仅克隆几个属性,但是如果这个时候我们又需要使用克隆进行复制一个完整对象(所有属性值),这个时候一个克隆方式不能满足两种需求。 这个和我们的单一职责相违背了。

类图

在这里插入图片描述

IRoleStateMemento:备忘录接口(为了避免管理者Caretaker访问到其备忘录类中的属性,该接口是一个空接口没有任何方法)

RoleStateMemento:具体备忘录类 (Memento)

RoleStateCaretaker:备忘录管理者(Caretaker)

Role:游戏角色类 (Originator 发起人)

Client:客户端测试

代码实例

IRoleStateMemento 备忘录接口

/**
 * @author duanyimiao
 * @create 2018-10-11 8:30 PM
 * @description 为了保证管理备忘录类不能操作和获取其内部数据,此时的属性需要使用一个没有实现方法的接口,并且该接口由RoleStateMemento类实现
 **/
public interface IRoleStateMemento {
}

Role 游戏角色类(里面包含了一个备忘录类)


/**
 * @author duanyimiao
 * @create 2018-10-11 8:05 PM
 * @description 游戏角色类(Originator发起人)
 **/
public class Role {
    //生命力
    private int vitality;
    //攻击力
    private int attack;
    //防御力
    private int defense;

    public void initState() {
        this.vitality = 100;
        this.attack = 100;
        this.defense = 100;
    }

    public RoleStateMemento createRoleStateMemento() {
        return new RoleStateMemento(vitality, attack, defense);
    }

    public void setRoleStateMemento(IRoleStateMemento iroleStateMemento) {
        RoleStateMemento roleStateMemento = (RoleStateMemento) iroleStateMemento;
        this.vitality = roleStateMemento.getVitality();
        this.attack = roleStateMemento.getAttack();
        this.defense = roleStateMemento.getDefense();
    }

    public void fight() {
        this.vitality = 0;
        this.attack = 0;
        this.defense = 0;
    }

    public void displayState() {
        System.out.println("vitality=" + vitality + " attack=" + attack + " defense=" + defense);
    }

    public int getVitality() {
        return vitality;
    }

    public void setVitality(int vitality) {
        this.vitality = vitality;
    }

    public int getAttack() {
        return attack;
    }

    public void setAttack(int attack) {
        this.attack = attack;
    }

    public int getDefense() {
        return defense;
    }

    public void setDefense(int defense) {
        this.defense = defense;
    }

    /**
     * 角色状态备忘录类(Memento 备忘录类)
     */
    private class RoleStateMemento implements IRoleStateMemento {
        //以下为需要备份Role对象的属性
        //生命力
        private int vitality;
        //攻击力
        private int attack;
        //防御力
        private int defense;

        public RoleStateMemento(int vitality, int attack, int defense) {
            this.vitality = vitality;
            this.attack = attack;
            this.defense = defense;
        }

        public int getVitality() {
            return vitality;
        }

        public void setVitality(int vitality) {
            this.vitality = vitality;
        }

        public int getAttack() {
            return attack;
        }

        public void setAttack(int attack) {
            this.attack = attack;
        }

        public int getDefense() {
            return defense;
        }

        public void setDefense(int defense) {
            this.defense = defense;
        }
    }

}

RoleStateCaretaker 备忘录管理者(里面包含一个由备忘录实现的接口)

/**
 * @author duanyimiao
 * @create 2018-10-11 8:11 PM
 * @description 管理备忘录的类(Caretaker 备忘录管理类)
 **/
public class RoleStateCaretaker {
    //为了保证管理备忘录类不能操作和获取其内部数据,此时的属性需要使用一个没有实现方法的接口,并且该接口由RoleStateMemento类实现
    //private RoleStateMemento roleStateMemento;
    //这个是一个空接口
    private IRoleStateMemento iRoleStateMemento;

    public void saveRoleStateMemento(IRoleStateMemento iRoleStateMemento) {
        this.iRoleStateMemento = iRoleStateMemento;
    }

    public IRoleStateMemento retrieveRoleStateMemento() {
        return iRoleStateMemento;
    }
}

Client 客户端测试类

/**
 * @author duanyimiao
 * @create 2018-10-11 8:17 PM
 * @description
 **/
public class Client {
    public static void main(String[] args) {
        Role role = new Role();
        role.initState();
        role.displayState();

        //在打boss之前游戏进度保存
        IRoleStateMemento roleStateMemento = role.createRoleStateMemento();
        //将备忘录对象交给管理员进行保存
        RoleStateCaretaker roleStateCaretaker = new RoleStateCaretaker();
        roleStateCaretaker.saveRoleStateMemento(roleStateMemento);
        //打boss
        role.fight();
        role.displayState();

        //恢复之前的对象状态
        role.setRoleStateMemento(roleStateCaretaker.retrieveRoleStateMemento());
        role.displayState();

    }
}

输出结果

vitality=100 attack=100 defense=100
vitality=0 attack=0 defense=0
vitality=100 attack=100 defense=100
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值