Java设计模式--备忘录模式

简介: 备忘录模式(别名:标记)在不破坏封装性的前提下,捕捉一个对象的内部状态,并在该对象之外保存这个状态,这样以后就可将该对象恢复到原先保存的状态。Memento Pattern(Another Name: Token)Without violating encapsulation, capture and externalize an object origina

备忘录模式(别名:标记)

在不破坏封装性的前提下,捕捉一个对象的内部状态,并在该对象之外保存这个状态,这样以后就可将该对象恢复到原先保存的状态。

Memento Pattern(Another Name: Token)

Without violating encapsulation, capture and externalize an object original state so that the object can be restored to this state later.

类图

模式的结构与使用

备忘录模式的结构中包括三种角色。
+ 原发者(Originator):需要在某个时刻保存其状态的对象。原发者负责创建备忘录,比如使用createMemento()方法创建一个备忘录,然后原发者使用该备忘录记录自己的状态。当原发者需要恢复某个时刻的状态时,它通过获得相应备忘录中的数据来恢复那个时刻的状态,比如原发者调用restoreFromMemento(Memento menm)方法,并通过参数mem指定的备忘录恢复状态。
+ 备忘录(Memento):负责存储原发者状态的对象,创建备忘录的类和创建原发者的类在同一个包中,该类提供的访问数据的方法都是友好方法,使得只有和原发者在同一个包中的类的实例才可以访问备忘录中的数据。
+ 负责人(Caretaker):负责管理保存备忘录的对象。负责人如果不和原发者在同一个包中,就不能对备忘录中的内容进行修改或读取。如果需要将备忘录保存到磁盘,负责人可以使用对象流将备忘录写入文件。

简单的例子

Memento的备忘录类Memento.java

package Memento;

import java.io.Serializable;

public class Memento implements Serializable {
    private long state;

    void setPositionState(long state) {
        this.state = state;
    }

    long getPosition() {
        return state;
    }
}

一个小的工具类ReadPhrase.java

ppackage Memento;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;

public class ReadPhrase {
    long readPosition;
    File file;
    RandomAccessFile in;
    String phrase = null;

    public ReadPhrase(File file) {
        this.file = file;
        try {
            in = new RandomAccessFile(file, "r");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }

    public Memento createMemento() {
        Memento mem = new Memento();
        System.out.println("----" + readPosition);
        mem.setPositionState(readPosition);
        return mem;
    }

    public void restoreFromMemento(Memento mem) {
        readPosition = mem.getPosition();
    }

    public String readLine() {
        try {
            in.seek(readPosition);
            phrase = in.readLine();
            if (phrase != null) {
                byte b[] = phrase.getBytes("UTF-8");
                phrase = new String(b);
            }
            readPosition = in.getFilePointer();
            System.out.println("readPosition:" + readPosition);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return phrase;
    }

    public void closeRead() {
        try {
            in.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

负责人的类Caretaker.java

package Memento;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class Caretaker {
    File file;
    private Memento memento = null;

    public Caretaker() {
        file = new File("saveObject.txt");
    }

    public Memento getMemento() {
        if (file.exists()) {
            try {
                FileInputStream in = new FileInputStream("saveObject.txt");
                ObjectInputStream inObject = new ObjectInputStream(in);
                memento = (Memento) inObject.readObject();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return memento;
    }

    public void saveMemento(Memento memento) {
        FileOutputStream out;
        try {
            out = new FileOutputStream("D:/09soft/MyEclipse 10/yanning/saveObject.txt");
            ObjectOutputStream outObject = new ObjectOutputStream(out);
            outObject.writeObject(memento);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

测试类Application.java

package Memento;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.Scanner;

public class Application {

    public static void main(String[] args) {
        Scanner reader = new Scanner(System.in);
        ReadPhrase readPhrase = new ReadPhrase(new File("D:/09soft/MyEclipse 10/yanning/src/Memento/phrase.txt"));
        File favorPhrase = new File("favorPhrase.txt");
        RandomAccessFile out = null;
        try {
            out = new RandomAccessFile(favorPhrase, "rw");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        System.out.println("是否从上次读取的位置继续读取成语(输入y或n)");
        String answer = reader.nextLine();
        if (answer.startsWith("y")||answer.startsWith("Y")) {
            Caretaker caretaker = new Caretaker();   //创建负责人
            Memento memento = caretaker.getMemento(); //得到备忘录
            if (memento != null) {
                readPhrase.restoreFromMemento(memento);  //使用备忘录恢复状态
            }
            String phrase = null;
            while((phrase = readPhrase.readLine()) != null) {
                System.out.println(phrase);
                System.out.println("是否将该成语保存到" + favorPhrase.getName());
                answer = reader.nextLine();
                if (answer.startsWith("y")||answer.startsWith("Y")) {
                    try {
                        out.seek(favorPhrase.length());
                        byte[] b = phrase.getBytes();
                        out.write(b);
                        out.write(' ');
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("是否继续读取成语?(输入y或n)");
                answer = reader.nextLine();
                if (answer.startsWith("y")||answer.startsWith("Y")) {
                    continue;
                } else {
                    readPhrase.closeRead();
                    caretaker.saveMemento(readPhrase.createMemento());
                    try {
                        out.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    System.exit(0);
                }
            }
            System.out.println("读完全部成语");
        }
        System.exit(0);
    }
}

备忘录模式的优点

  • 备忘录模式使用备忘录可以把原发者的内部状态保存起来,使只有很“亲密的”的对象可以访问备忘录中的数据。
  • 备忘录模式强调了类设计单一责任原则,即将状态的刻画和保存分开。

适用备忘录模式的情景

下列情况之一就可以考虑使用备忘录模式

  • 必须保存一个对象在某一时刻的全部或部分状态,以便在需要时恢复该对象先前的状态。
  • 一个对象不想通过提供public权限的,诸如getXXX()的方法让其他对象得到自己的内部状态。

注:如果备忘录需要存储大量的数据或非常频繁地创建备忘录,可能会导致非常大的存储开销。

下载源码请到

MyGitHub

目录
相关文章
|
2月前
|
设计模式 Java Spring
Java 设计模式之责任链模式:优雅处理请求的艺术
责任链模式通过构建处理者链,使请求沿链传递直至被处理,实现发送者与接收者的解耦。适用于审批流程、日志处理等多级处理场景,提升系统灵活性与可扩展性。
247 2
|
2月前
|
设计模式 网络协议 数据可视化
Java 设计模式之状态模式:让对象的行为随状态优雅变化
状态模式通过封装对象的状态,使行为随状态变化而改变。以订单为例,将待支付、已支付等状态独立成类,消除冗长条件判断,提升代码可维护性与扩展性,适用于状态多、转换复杂的场景。
281 0
|
4月前
|
设计模式 缓存 Java
Java设计模式(二):观察者模式与装饰器模式
本文深入讲解观察者模式与装饰器模式的核心概念及实现方式,涵盖从基础理论到实战应用的全面内容。观察者模式实现对象间松耦合通信,适用于事件通知机制;装饰器模式通过组合方式动态扩展对象功能,避免子类爆炸。文章通过Java示例展示两者在GUI、IO流、Web中间件等场景的应用,并提供常见陷阱与面试高频问题解析,助你写出灵活、可维护的代码。
|
2月前
|
设计模式 算法 搜索推荐
Java 设计模式之策略模式:灵活切换算法的艺术
策略模式通过封装不同算法并实现灵活切换,将算法与使用解耦。以支付为例,微信、支付宝等支付方式作为独立策略,购物车根据选择调用对应支付逻辑,提升代码可维护性与扩展性,避免冗长条件判断,符合开闭原则。
280 35
|
2月前
|
设计模式 消息中间件 传感器
Java 设计模式之观察者模式:构建松耦合的事件响应系统
观察者模式是Java中常用的行为型设计模式,用于构建松耦合的事件响应系统。当一个对象状态改变时,所有依赖它的观察者将自动收到通知并更新。该模式通过抽象耦合实现发布-订阅机制,广泛应用于GUI事件处理、消息通知、数据监控等场景,具有良好的可扩展性和维护性。
241 8
|
7月前
|
设计模式 存储 Java
【设计模式】【行为型模式】备忘录模式(Memento)
一、入门 什么是备忘录模式? 备忘录模式(Memento Pattern)是一种行为设计模式,用于在不破坏封装性的前提下,捕获并外部化一个对象的内部状态,以便在需要时恢复该状态。它通常用于实现撤销操作
222 8
|
7月前
|
设计模式 缓存 安全
【高薪程序员必看】万字长文拆解Java并发编程!(8):设计模式-享元模式设计指南
🌟 ​大家好,我是摘星!​ 🌟今天为大家带来的是并发编程中的经典对象复用设计模式-享元模式,废话不多说让我们直接开始。
167 0
|
4月前
|
设计模式 安全 Java
Java设计模式(一):单例模式与工厂模式
本文详解单例模式与工厂模式的核心实现及应用,涵盖饿汉式、懒汉式、双重检查锁、工厂方法、抽象工厂等设计模式,并结合数据库连接池与支付系统实战案例,助你掌握设计模式精髓,提升代码专业性与可维护性。
|
4月前
|
设计模式 XML 安全
Java枚举(Enum)与设计模式应用
Java枚举不仅是类型安全的常量,还具备面向对象能力,可添加属性与方法,实现接口。通过枚举能优雅实现单例、策略、状态等设计模式,具备线程安全、序列化安全等特性,是编写高效、安全代码的利器。
|
9月前
|
设计模式 存储 Java
【再谈设计模式】备忘录模式~对象状态的守护者
备忘录模式属于行为型设计模式。它的主要目的是在不破坏对象封装性的前提下,捕获并外部化一个对象的内部状态,以便之后可以将该对象恢复到这个状态。原发器(Originator):创建一个备忘录,用于记录当前时刻它的内部状态。原发器还可以使用备忘录来恢复其内部状态。备忘录(Memento):存储原发器对象的内部状态。备忘录应该防止原发器以外的其他对象访问其内部状态。负责人(Caretaker):负责保存备忘录,但不能对备忘录的内容进行操作或检查。
324 82