设计模式学习第十九节 备忘录模式

备忘录模式

      • 概述
      • 案例实现
      • 总结

概述

    基本介绍
    1、备忘录模式(Memento Pattern):在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样以后就可以将该对象恢复带原先保存的状态。备忘录模式属于行为型模式。
    2、备忘录模式提供了一种状态恢复的实现机制,使得用户可以方便的回退到一个特点的历史步骤,当新的状态无效或者存在问题时,可以使用暂存起来的备忘录将其恢复。
    3、备忘录对象主要用来记录一个对象的某种状态,或者默写数据,可以从备忘录对象中获取原来的数据进行恢复操作,比如:在象棋对局中悔棋的操作、游戏中节点的保存等等,可以利用备忘录模式。
    备忘录模式原理类图分析:
设计模式学习第十九节 备忘录模式_第1张图片
    角色分析
    1、Originator:源类,是一个普通类,可以创建一个备忘录类,并且存储它的当前状态,也可以使用备忘录来恢复其内部状态,一般需要保存内部状态的类设计为源类。
    2、Memento:备忘录,存储源类的内部状态,根据源类来决定保存那些内部状态,需要注意的是,除了源类本身和负责人类,备忘录对象不能直接供其它类使用。
    3、Caretaker:负责人类,也叫做管理者,它负责保存备忘录,但是不能对备忘录的内容进行检查和操作,负责人类中可以存储一个或多个备忘录对象,只负责存储对象,不能修改也无需知道对象的实现细节。
    代码模拟原理类图

package com.example.pattern.memento;

import lombok.Getter;
import lombok.Setter;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.List;

/**
 * 备忘录模式
 */
@Setter
@Getter
public class Originator {
      // 源类

    private String name; // 内部属性

    private String status; // 状态

    public Originator(String name, String status) {
     
        this.name = name;
        this.status = status;
    }

    public Memento createMemento() {
      // 保存备忘录
        return new Memento(this);
    }

    public void resetMemento(Memento memento) {
      // 根据备忘录对象恢复源类状态
        this.status = memento.getStatus();
    }

    @Override
    public String toString() {
     
        return "Originator{" +
                "name='" + name + '\'' +
                ", status='" + status + '\'' +
                '}';
    }
}

@Getter
class Memento {
      // 备忘录类 不对外提供操作

    private String status;

    public Memento(Originator originator) {
     
        this.status = originator.getStatus();
    }

}

class Caretaker {
      // 管理类 守护着对象

    private List<Memento> mementoList;

    public void add(Memento memento) {
     
        if (CollectionUtils.isEmpty(mementoList)) {
     
            mementoList = new ArrayList<>();
        }
        mementoList.add(memento);
    }

    public Memento getMementoByIndex(int index) {
     
        if (CollectionUtils.isEmpty(mementoList)) {
     
            throw new RuntimeException("备忘录列表为空");
        }
        return mementoList.get(index);
    }

}

class Client {
     
    public static void main(String[] args) {
     
        Caretaker caretaker = new Caretaker();
        Originator o = new Originator("张三", "状态1");
        System.out.println(o);
        caretaker.add(o.createMemento());
        // 变更为状态2
        o.setStatus("状态2");
        caretaker.add(o.createMemento());
        System.out.println(o);
        // 变更为状态3
        o.setStatus("状态3");
        caretaker.add(o.createMemento());
        System.out.println(o);
        // 恢复到状态1
        o.resetMemento(caretaker.getMementoByIndex(0));
        System.out.println(o);
    }
}

案例实现

    游戏角色存档问题

package com.example.pattern.memento.improve;

import lombok.Getter;
import lombok.Setter;
import org.springframework.util.CollectionUtils;

import java.util.HashMap;
import java.util.Map;

/**
 * 使用备忘录模式实现游戏角色存档问题
 *
 * @author zjt
 * @date 2021-01-05
 */
@Getter
@Setter
public class GameRole {
      // 源类

    private String roleName; // 角色名称

    private String gameLevel; // 游戏关卡

    private float HP; // 生命值

    private float MP; // 法力值

    public GameRole(String roleName, String gameLevel, float HP, float MP) {
     
        this.roleName = roleName;
        this.gameLevel = gameLevel;
        this.HP = HP;
        this.MP = MP;
    }

    public GameMemento createGameMemento() {
      // 创建备忘录
        return new GameMemento(this);
    }

    public void recoverGameMemento(GameMemento memento) {
     
        this.roleName = memento.getRoleName();
        this.gameLevel = memento.getGameLevel();
        this.HP = memento.getHP();
        this.MP = memento.getMP();
    }

    public void exit() {
     
        this.roleName = null;
        this.gameLevel = null;
        this.MP = 0;
        this.HP = 0;
    }

    @Override
    public String toString() {
     
        return "GameRole{" +
                "roleName='" + roleName + '\'' +
                ", gameLevel='" + gameLevel + '\'' +
                ", HP=" + HP +
                ", MP=" + MP +
                '}';
    }
}

@Getter
class GameMemento {
      // 备忘录类

    private String roleName; // 角色名称

    private String gameLevel; // 游戏关卡

    private float HP; // 生命值

    private float MP; // 法力值

    public GameMemento(GameRole gameRole) {
     
        this.roleName = gameRole.getRoleName();
        this.gameLevel = gameRole.getGameLevel();
        this.HP = gameRole.getHP();
        this.MP = gameRole.getMP();
    }
}

class GameCaretaker {
      // 备忘录管理类

    // 只保存最近一次的存档记录,
    private Map<String, GameMemento> mementoMap = new HashMap<>();

    public void addGameMemento(GameMemento memento) {
      // 添加备忘录 添加存档信息
        if (null != memento) {
     
            mementoMap.put(memento.getRoleName(), memento);
        }
    }

    public GameMemento getGameMemento(String roleName) {
      // 根据角色名称获取存档信息
        if (CollectionUtils.isEmpty(mementoMap)) {
     
            throw new RuntimeException("存档读取失败");
        }
        GameMemento memento = mementoMap.get(roleName);
        if (memento == null) {
     
            throw new RuntimeException("存档读取失败");
        }
        return memento;
    }

}

class GameClient {
     
    public static void main(String[] args) {
     
        // 创建备忘录管理者
        GameCaretaker caretaker = new GameCaretaker();
        // 创建用户角色
        GameRole role1 = new GameRole("张三", "1-1", 100, 100);
        role1.setGameLevel("3-4");
        role1.setHP(50);
        role1.setMP(47);
        caretaker.addGameMemento(role1.createGameMemento());
        System.out.println(role1);
        System.out.println("用户使用张三退出了游戏");
        role1.exit();
        System.out.println(role1);
        System.out.println("--------------");
        System.out.println("用户重新进入了游戏,并使用张三选择读档");
        GameMemento memento = caretaker.getGameMemento("张三");
        role1.recoverGameMemento(memento);
        System.out.println(role1);
    }
}

总结

    备忘录模式在很多软件的使用过程中普遍存在,但是在应用软件开发中,它的使用频率并不太高,因为现在很多基于窗体和浏览器的应用软件并没有提供撤销操作。如果需要为软件提供撤销功能,备忘录模式无疑是一种很好的解决方案。在一些字处理软件、图像编辑软件、数据库管理系统等软件中备忘录模式都得到了很好的应用。
    优点
    1、它提供了一种状态恢复的实现机制,使得用户可以方便地回到一个特定的历史步骤,当新的状态无效或者存在问题时,可以使用暂时存储起来的备忘录将状态复原。
    2、备忘录实现了对信息的封装,一个备忘录对象是一种原发器对象状态的表示,不会被其他代码所改动。备忘录保存了原发器的状态,采用列表、堆栈等集合来存储备忘录对象可以实现多次撤销操作。
    缺点
    1、资源消耗过大,如果需要保存的原发器类的成员变量太多,就不可避免需要占用大量的存储空间,每保存一次对象的状态都需要消耗一定的系统资源。
    2、为了节约内存,备忘录模式可以和原型模式配合使用。

你可能感兴趣的:(设计模式,设计模式,java)