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

目录
相关文章
|
18天前
|
设计模式 Java 开发者
设计模式揭秘:Java世界的七大奇迹
【4月更文挑战第7天】探索Java设计模式:单例、工厂方法、抽象工厂、建造者、原型、适配器和观察者,助你构建健壮、灵活的软件系统。了解这些模式如何提升代码复用、可维护性,以及在特定场景下的应用,如资源管理、接口兼容和事件监听。掌握设计模式,但也需根据实际情况权衡,打造高效、优雅的软件解决方案。
|
19天前
|
设计模式 存储 Java
23种设计模式,享元模式的概念优缺点以及JAVA代码举例
【4月更文挑战第6天】享元模式(Flyweight Pattern)是一种结构型设计模式,旨在通过共享技术有效地支持大量细粒度对象的重用。这个模式在处理大量对象时非常有用,特别是当这些对象中的许多实例实际上可以共享相同的状态时,从而可以减少内存占用,提高程序效率
35 4
|
19天前
|
设计模式 Java 中间件
23种设计模式,适配器模式的概念优缺点以及JAVA代码举例
【4月更文挑战第6天】适配器模式(Adapter Pattern)是一种结构型设计模式,它的主要目标是让原本由于接口不匹配而不能一起工作的类可以一起工作。适配器模式主要有两种形式:类适配器和对象适配器。类适配器模式通过继承来实现适配,而对象适配器模式则通过组合来实现
30 4
|
23天前
|
设计模式 Java 数据库
Java设计模式精讲:让代码更优雅、更可维护
【4月更文挑战第2天】**设计模式是解决软件设计问题的成熟方案,分为创建型、结构型和行为型。Java中的单例模式确保类仅有一个实例,工厂方法模式让子类决定实例化哪个类。适配器模式则协调不兼容接口间的合作。观察者模式实现了一对多依赖,状态变化时自动通知相关对象。学习和适当应用设计模式能提升代码质量和可维护性,但需避免过度使用。设计模式的掌握源于实践与不断学习。**
Java设计模式精讲:让代码更优雅、更可维护
|
27天前
|
设计模式 安全 Java
在Java中即指单例设计模式
在Java中即指单例设计模式
18 0
|
18天前
|
设计模式 监控 Java
设计模式 - 观察者模式(Observer):Java中的战术与策略
【4月更文挑战第7天】观察者模式是构建可维护、可扩展系统的关键,它在Java中通过`Observable`和`Observer`实现对象间一对多的依赖关系,常用于事件处理、数据绑定和同步。该模式支持事件驱动架构、数据同步和实时系统,但需注意避免循环依赖、控制通知粒度,并关注性能和内存泄漏问题。通过明确角色、使用抽象和管理观察者注册,可最大化其效果。
|
1天前
|
设计模式 算法 Java
[设计模式Java实现附plantuml源码~行为型]定义算法的框架——模板方法模式
[设计模式Java实现附plantuml源码~行为型]定义算法的框架——模板方法模式
|
1天前
|
设计模式 JavaScript Java
[设计模式Java实现附plantuml源码~行为型] 对象状态及其转换——状态模式
[设计模式Java实现附plantuml源码~行为型] 对象状态及其转换——状态模式
|
1天前
|
设计模式 存储 JavaScript
[设计模式Java实现附plantuml源码~创建型] 多态工厂的实现——工厂方法模式
[设计模式Java实现附plantuml源码~创建型] 多态工厂的实现——工厂方法模式
|
1天前
|
设计模式 Java Go
[设计模式Java实现附plantuml源码~创建型] 集中式工厂的实现~简单工厂模式
[设计模式Java实现附plantuml源码~创建型] 集中式工厂的实现~简单工厂模式