设计模式之备忘录模式

前言:

备忘录模式(Memento Pattern)在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样以后就可以将对象恢复到原先保存的状态。

一.备忘录模式简介

备忘录模式(Memento Pattern)适用于功能比较复杂,但需要维护和记录的历史类,或者需要保存属性只是众多属性中的一小部分时,用备忘录模式可以将信息还原。

二.备忘录模式的实例讲解

案例:游戏主角在战斗中死亡后复活,可以通过备忘录模式实现。

1.产品设计UML类图

这里写图片描述
(图片加载慢,多刷新几下,耐心等待……)

注:管理者类Caretaker和备忘录类Memento是聚合关系,Caretaker包含Memento,但不是Memento的一部分。

聚合关系:表示一种弱的"拥有"关系,体现的是A对象可以包含B对象,但B对象不是A对象的一部分。
2.游戏角色类(发起人)

设计分析:创建一个备忘录类(Memento),实现保存游戏角色的状态,并且可以恢复游戏角色的状态。可以根据需求,有选择的决定保存那些状态,这里只保存游戏角色的生命值hp、攻击力atk、防御力def

package com.patttern.originator;

import com.patttern.memento.Memento;

/**
 * 创建一个备忘录,储存状态,用于还原
 */
public class Originator {
    // 生命值
    private int hp;
    // 攻击力
    private int atk;
    // 防御力
    private int def;
    // 状态
    private String state;
    // 角色姓名
    private String name;

    //显示当前状态
    public void showState() {
        System.out.println(getName() + "当前状态:生命值:" + getHp() + ",攻击力:" + getAtk() + ",防御力" + getDef());
    }
    //初始化角色状态
    public void getInitState(String name) {
        setName(name);
        setHp(1000);
        setAtk(80);
        setDef(50);
    }

    //被击杀,状态清零
    public void killed() {
        setHp(0);
        setAtk(0);
        setDef(0);
    }

    //创建备忘录对象
    public Memento CreateMemento() {
        return new Memento();
    }
    //保存角色状态到备忘录中
    public Memento saveState() {

        return new Memento(hp, atk, def);
    }
    //恢复数据
    public void recoveryState(Memento memento) {
        this.hp = memento.getHp();
        this.atk = memento.getAtk();
        this.def = memento.getDef();
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getState() {
        return state;
    }

    public void setState(String state) {
        this.state = state;
    }

    public int getHp() {
        return hp;
    }

    public void setHp(int hp) {
        this.hp = hp;
    }

    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;
    }

}
3.备忘录类

设计分析: 储存游戏角色的状态,并禁止该游戏角色以外的其他对象对备忘录的访问。备忘录有两个接口,一个宽接口对游戏角色(Originator)开放,使游戏角色可以恢复状态数据;另一个窄接口,对管理者(Caretaker)公开,它只能将备忘录传递给其他对象。

ppackage com.patttern.memento;

/**
 * 备忘录:用于保存状态数据
 * 
 */
public class Memento {

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

    public Memento() {
    }

    public Memento(int hp, int atk, int def) {
        this.hp = hp;
        this.atk = atk;
        this.def = def;
    }

    public int getHp() {
        return hp;
    }

    public void setHp(int hp) {
        this.hp = hp;
    }

    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;
    }

}
4.管理者类(Caretaker)

设计分析: 维护一个备忘录Memento对象的具体实例,只能管理备忘录,但不能对其内容操作和检查。

为什么不直接在客户端中维护备忘录Memento,而非要在Caretaker中维护呢?这是因为开发中要符合迪米特法则,让客户端和备忘录Memento不直接通信,而在管理者的帮助下完成通信。

迪米特法则:如果两个类不直接通信,那么这两个类就不应当发生直接的相互作用。如果其中一个类要调用另一个类中某个方法的话,可通过第三者转发这个调用。

代码如下:

package com.patttern.caretaker;

import com.patttern.memento.Memento;
/**
 * 管理角色状态
 *
 */
public class Caretaker {
    //管理备忘录对象
    private Memento memento;

    public Memento getMemento() {
        return memento;
    }

    public void setMemento(Memento memento) {
        this.memento = memento;
    }
}
5.客户端中使用

模拟英雄盖伦的生命周期,创建人物-备份状态-战斗死亡-复活恢复状态。

package com.patttern.client;

import com.patttern.caretaker.Caretaker;
import com.patttern.originator.Originator;

public class Client {
    public static void main(String[] args) {
        //初始化
        Originator garen = new Originator();
        garen.getInitState("盖伦");
        garen.showState();
        //备份状态
        Caretaker caretaker = new Caretaker();
        caretaker.setMemento(garen.saveState());

        //在战斗中被杀
        garen.killed();
        garen.showState();

        //复活-恢复状态
        garen.recoveryState(caretaker.getMemento());
        garen.showState();

    }
}

6.运行结果展示
盖伦当前状态:生命值:1000,攻击力:80,防御力50
盖伦当前状态:生命值:0,攻击力:0,防御力0
盖伦当前状态:生命值:1000,攻击力:80,防御力50
7.源码下载

本文示例代码下载地址:点击下载

三.总结:

备忘录模式适合应用于复杂的,但需要维护或记录属性历史的类,或者需要保存的属性只是众多属性的一部分时,Originator类可以根据备忘录中的信息还原到以前状态。

1.备忘录模式的优点
  • 方便用户恢复到某个历史状态,如撤销功能。
  • 实现了对状态信息的封装,用户不需要关心保存细节。
2.备忘录模式的缺点
  • 若果状态成员变量过多,每次保存都会消耗很多内存资源。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值