备忘录模式(学习笔记)

  1. 意图

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

  2. 动机

   假如你开发一款文字编辑器应用程序。除了简单的文字编辑功能外,编辑器还要有设置文本格式和插入内嵌图片的等功能。后来,决定添加一个让用户能撤销施加在文本上的任何操做。canvas

  刚开始,打算用直接的方式实现该功能:程序在执行任何操做前会记录全部对象的状态,并将其保存。当须要撤销某个操做时,程序将从历史记录中得到最近的快照,而后使用它来恢复全部对象的状态。dom

     

  可是,如何生成这些快照呢?先想到的是遍历对象的全部成员变量并将其数值复制保存。这须要对象自己没有严格的访问权限限制,可是,大多数对象会使用私有成员变量来存储重要数据,这样别人就没法轻易查看其中的内容。编辑器

  假设全部对象都是public的,这种方式,仍存在其余的问题。将来,因为需求变化,可能会添加或删除一些成员变量。这须要对负责复制对象状态的类进行修改。ide

  另外,为了让其余对象能保存或读取快照,极可能须要将快照的成员变量设为公有,而这将暴漏被复制对象的状态。其余类也会对快照类的每一个小改动产生依赖。咱们彷佛走进了一个死胡同:要么暴漏类的全部内部细节而使其过去脆弱;要么限制对其状态的访问权限而没法生成快照。this

  咱们刚刚遇到的问题,都是封装破损形成的。一些对象试图超出其职责范围的工做。因为在执行某些行为时须要获取数据,因此它们侵入了其余对象的私有空间,而不是让这些对象来完成实际的工做spa

  备忘录模式将建立状态快照(Snapshot的工做委派给实际状态的拥有者原发器(Originator对象这样其余对象就再也不须要从 “外部 复制编辑器状态了,编辑器类拥有其状态的彻底访问权所以能够自行生成快照。模式建议将对象状态的副本存储在一个名为备忘录 (Memento 的特殊对象中 除了建立备忘录的对象外 任何对象都不能访问备忘录的内容 其余对象必须使用受限接口与备忘录进行交互 它们能够获取快照的元数据 (建立时间和操做名称等 但不能获取快照中原始对象的状态 设计

  3. 适用性

  • 必须保存一个对象在某个时刻的(部分)状态,这样之后须要时他才能恢复到先前的状态
  • 若是一个接口让其余对象直接获得这些状态,将会暴露对象的实现细节并破坏对象的封装性

  4. 结构

        

  5. 效果

  1) 能够在不破坏对象封装状况的前提下建立对象状态快照rest

  2) 简化了原发器   在其余的保持封装性的设计中,Originator负责保持客户请求过的内部状态版本。这就把全部存储管理的责任交给了Originator。让客户管理请求的状态能够简化Originator,而且使得客户工做结束时无需通知原发器code

  3) 使用备忘录可能代价很高   若是原生器在生成备忘录时必须拷贝并存储大量的信息,或者客户很是频繁地建立备忘录和恢复原发器的状态,可能致使很大的开销。除非封装和恢复Originator状态的开销不大。

    -存储增量式改变    若是备忘录的建立及其返回的顺序是可预测的,备忘录能够仅存储原发器内部状态的增量改变

    例如,一个包含可撤销命令的历史列表可以使用备忘录, 以保证命令被取消时他们能够恢复到正确的状态。历史列表定义了一个特定的顺序,按照这个顺序命令能够被撤销和重作。这意味着一个命令能够只存储一个命令所产生的增量改变而不是它所影响的每个对象的完整状态。

  6. 代码实现    

  假设开发一个图形编辑器的撤销功能,其容许修改屏幕上形状的颜色和位置。但任何修改均可被撤销和重复。“撤销” 功能基于备忘录和命令模式的合做。编辑器记录命令的执行历史。在执行任何命令以前,都会生成备份并将其链接到一个命令对象。而在执行完成后,会将已执行的命令放入历史记录中。当用户请求撤销操做时,编辑器将从历史记录中获取最近的命令,恢复在该命令内部保存的状态备份。若是用户再次请求撤销操做,编辑器将恢复历史记录中的下一个命令,以此类推。被撤销的命令都将保存在历史记录中,直至用户对屏幕上的形状进行了修改。这对恢复被撤销的命令来讲相当重要

  editor/Editor.java:编辑器代码

package memento.editor;

import memento.history.History;
import memento.history.Memento;
import command.commands.Command;
import composite.shapes.CompoundShape;
import memento.shapes.Shape;

import javax.swing.*;
import java.io.*;
import java.util.Base64;

/**
 * @author GaoMing
 * @date 2021/7/25 - 20:47
 */
public class Editor extends JComponent {
    private Canvas canvas;
    private CompoundShape allShapes = new CompoundShape();
    private History history;

    public Editor() {
        canvas = new Canvas(this);
        history = new History();
    }

    public void loadShapes(Shape... shapes) {
        allShapes.clear();
        allShapes.add(shapes);
        canvas.refresh();
    }

    public CompoundShape getShapes() {
        return allShapes;
    }

    public void execute(Command c) {
        history.push(c, new Memento(this));
        c.execute();
    }

    public void undo() {
        if (history.undo())
            canvas.repaint();
    }

    public void redo() {
        if (history.redo())
            canvas.repaint();
    }

    public String backup() {
        try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(baos);
            oos.writeObject(this.allShapes);
            oos.close();
            return Base64.getEncoder().encodeToString(baos.toByteArray());
        } catch (IOException e) {
            return "";
        }
    }

    public void restore(String state) {
        try {
            byte[] data = Base64.getDecoder().decode(state);
            ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(data));
            this.allShapes = (CompoundShape) ois.readObject();
            ois.close();
        } catch (ClassNotFoundException e) {
            System.out.print("ClassNotFoundException occurred.");
        } catch (IOException e) {
            System.out.print("IOException occurred.");
        }
    }
}

  editor/Canvas.java: 画布代码

package memento.editor;

import memento.commands.ColorCommand;
import memento.commands.MoveCommand;
import memento.shapes.Shape;

import javax.swing.*;
import javax.swing.border.Border;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;

/**
 * @author GaoMing
 * @date 2021/7/25 - 20:47
 */
public class Canvas extends java.awt.Canvas{
    private Editor editor;
    private JFrame frame;
    private static final int PADDING = 10;

    Canvas(Editor editor) {
        this.editor = editor;
        createFrame();
        attachKeyboardListeners();
        attachMouseListeners();
        refresh();
    }

    private void createFrame() {
        frame = new JFrame();
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frame.setLocationRelativeTo(null);

        JPanel contentPanel = new JPanel();
        Border padding = BorderFactory.createEmptyBorder(PADDING, PADDING, PADDING, PADDING);
        contentPanel.setBorder(padding);
        contentPanel.setLayout(new BoxLayout(contentPanel, BoxLayout.Y_AXIS));
        frame.setContentPane(contentPanel);

        contentPanel.add(new JLabel("Select and drag to move."), BorderLayout.PAGE_END);
        contentPanel.add(new JLabel("Right click to change color."), BorderLayout.PAGE_END);
        contentPanel.add(new JLabel("Undo: Ctrl+Z, Redo: Ctrl+R"), BorderLayout.PAGE_END);
        contentPanel.add(this);
        frame.setVisible(true);
        contentPanel.setBackground(Color.LIGHT_GRAY);
    }

    private void attachKeyboardListeners() {
        addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                if ((e.getModifiers() & KeyEvent.CTRL_MASK) != 0) {
                    switch (e.getKeyCode()) {
                        case KeyEvent.VK_Z:
                            editor.undo();
                            break;
                        case KeyEvent.VK_R:
                            editor.redo();
                            break;
                    }
                }
            }
        });
    }

    private void attachMouseListeners() {
        MouseAdapter colorizer = new MouseAdapter() {
            @Override
            public void mousePressed(MouseEvent e) {
                if (e.getButton() != MouseEvent.BUTTON3) {
                    return;
                }
                Shape target = editor.getShapes().getChildAt(e.getX(), e.getY());
                if (target != null) {
                    editor.execute(new ColorCommand(editor, new Color((int) (Math.random() * 0x1000000))));
                    repaint();
                }
            }
        };
        addMouseListener(colorizer);

        MouseAdapter selector = new MouseAdapter() {
            @Override
            public void mousePressed(MouseEvent e) {
                if (e.getButton() != MouseEvent.BUTTON1) {
                    return;
                }

                Shape target = editor.getShapes().getChildAt(e.getX(), e.getY());
                boolean ctrl = (e.getModifiers() & ActionEvent.CTRL_MASK) == ActionEvent.CTRL_MASK;

                if (target == null) {
                    if (!ctrl) {
                        editor.getShapes().unSelect();
                    }
                } else {
                    if (ctrl) {
                        if (target.isSelected()) {
                            target.unSelect();
                        } else {
                            target.select();
                        }
                    } else {
                        if (!target.isSelected()) {
                            editor.getShapes().unSelect();
                        }
                        target.select();
                    }
                }
                repaint();
            }
        };
        addMouseListener(selector);


        MouseAdapter dragger = new MouseAdapter() {
            MoveCommand moveCommand;

            @Override
            public void mouseDragged(MouseEvent e) {
                if ((e.getModifiersEx() & MouseEvent.BUTTON1_DOWN_MASK) != MouseEvent.BUTTON1_DOWN_MASK) {
                    return;
                }
                if (moveCommand == null) {
                    moveCommand = new MoveCommand(editor);
                    moveCommand.start(e.getX(), e.getY());
                }
                moveCommand.move(e.getX(), e.getY());
                repaint();
            }

            @Override
            public void mouseReleased(MouseEvent e) {
                if (e.getButton() != MouseEvent.BUTTON1 || moveCommand == null) {
                    return;
                }
                moveCommand.stop(e.getX(), e.getY());
                editor.execute(moveCommand);
                this.moveCommand = null;
                repaint();
            }
        };
        addMouseListener(dragger);
        addMouseMotionListener(dragger);
    }

    public int getWidth() {
        return editor.getShapes().getX() + editor.getShapes().getWidth() + PADDING;
    }

    public int getHeight() {
        return editor.getShapes().getY() + editor.getShapes().getHeight() + PADDING;
    }

    void refresh() {
        this.setSize(getWidth(), getHeight());
        frame.pack();
    }

    public void update(Graphics g) {
        paint(g);
    }

    public void paint(Graphics graphics) {
        BufferedImage buffer = new BufferedImage(this.getWidth(), this.getHeight(), BufferedImage.TYPE_INT_RGB);
        Graphics2D ig2 = buffer.createGraphics();
        ig2.setBackground(Color.WHITE);
        ig2.clearRect(0, 0, this.getWidth(), this.getHeight());

        editor.getShapes().paint(buffer.getGraphics());

        graphics.drawImage(buffer, 0, 0, null);
    }
}
View Code

  history/History.java: 保存命令和备忘录的历史记录

package memento.history;

import memento.commands.Command;

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

/**
 * @author GaoMing
 * @date 2021/7/25 - 20:47
 */
public class History {
    private List<Pair> history = new ArrayList<Pair>();
    private int virtualSize = 0;

    private class Pair {
        Command command;
        Memento memento;
        Pair(Command c, Memento m) {
            command = c;
            memento = m;
        }

        private Command getCommand() {
            return command;
        }

        private Memento getMemento() {
            return memento;
        }
    }

    public void push(Command c, Memento m) {
        if (virtualSize != history.size() && virtualSize > 0) {
            history = history.subList(0, virtualSize - 1);
        }
        history.add(new Pair(c, m));
        virtualSize = history.size();
    }

    public boolean undo() {
        Pair pair = getUndo();
        if (pair == null) {
            return false;
        }
        System.out.println("Undoing: " + pair.getCommand().getName());
        pair.getMemento().restore();
        return true;
    }

    public boolean redo() {
        Pair pair = getRedo();
        if (pair == null) {
            return false;
        }
        System.out.println("Redoing: " + pair.getCommand().getName());
        pair.getMemento().restore();
        pair.getCommand().execute();
        return true;
    }

    private Pair getUndo() {
        if (virtualSize == 0) {
            return null;
        }
        virtualSize = Math.max(0, virtualSize - 1);
        return history.get(virtualSize);
    }

    private Pair getRedo() {
        if (virtualSize == history.size()) {
            return null;
        }
        virtualSize = Math.min(history.size(), virtualSize + 1);
        return history.get(virtualSize - 1);
    }
}

  history/Memento.java:备忘录类

package memento.history;
import memento.editor.Editor;

/**
 * @author GaoMing
 * @date 2021/7/25 - 20:48
 */
public class Memento {
    private String backup;
    private Editor editor;

    public Memento(Editor editor) {
        this.editor = editor;
        this.backup = editor.backup();
    }

    public void restore() {
        editor.restore(backup);
    }
}

  commands/Command.java: 基础命令类

package memento.commands;

/**
 * @author GaoMing
 * @date 2021/7/25 - 20:52
 */
public interface Command {
    String getName();
    void execute();
}

  commands/ColorCommand.java: 修改已选形状的颜色

package memento.commands;

import memento.editor.Editor;
import memento.shapes.Shape;

import java.awt.*;


/**
 * @author GaoMing
 * @date 2021/7/25 - 20:52
 */
public class ColorCommand implements Command{
    private Editor editor;
    private Color color;

    public ColorCommand(Editor editor, Color color) {
        this.editor = editor;
        this.color = color;
    }

    @Override
    public String getName() {
        return "Colorize: " + color.toString();
    }

    @Override
    public void execute() {
        for (Shape child : editor.getShapes().getSelected()) {
            child.setColor(color);
        }
    }
}

  commands/MoveCommand.java: 移动已选形状

package memento.commands;


import memento.editor.Editor;
import memento.shapes.Shape;

/**
 * @author GaoMing
 * @date 2021/7/25 - 20:53
 */
public class MoveCommand implements Command{
    private Editor editor;
    private int startX, startY;
    private int endX, endY;

    public MoveCommand(Editor editor) {
        this.editor = editor;
    }

    @Override
    public String getName() {
        return "Move by X:" + (endX - startX) + " Y:" + (endY - startY);
    }

    public void start(int x, int y) {
        startX = x;
        startY = y;
        for (Shape child : editor.getShapes().getSelected()) {
            child.drag();
        }
    }

    public void move(int x, int y) {
        for (Shape child : editor.getShapes().getSelected()) {
            child.moveTo(x - startX, y - startY);
        }
    }

    public void stop(int x, int y) {
        endX = x;
        endY = y;
        for (Shape child : editor.getShapes().getSelected()) {
            child.drop();
        }
    }

    @Override
    public void execute() {
        for (Shape child : editor.getShapes().getSelected()) {
            child.moveBy(endX - startX, endY - startY);
        }
    }
}

  shapes/Shape.java

package memento.shapes;

import java.awt.*;
import java.io.Serializable;

/**
 * @author GaoMing
 * @date 2021/7/25 - 20:55
 */
public interface Shape extends Serializable {
    int getX();
    int getY();
    int getWidth();
    int getHeight();
    void drag();
    void drop();
    void moveTo(int x, int y);
    void moveBy(int x, int y);
    boolean isInsideBounds(int x, int y);
    Color getColor();
    void setColor(Color color);
    void select();
    void unSelect();
    boolean isSelected();
    void paint(Graphics graphics);
}

  shapes/BaseShape.java

package memento.shapes;

import java.awt.*;

/**
 * @author GaoMing
 * @date 2021/7/25 - 20:56
 */
public abstract class BaseShape implements Shape{
    int x, y;
    private int dx = 0, dy = 0;
    private Color color;
    private boolean selected = false;

    BaseShape(int x, int y, Color color) {
        this.x = x;
        this.y = y;
        this.color = color;
    }

    @Override
    public int getX() {
        return x;
    }

    @Override
    public int getY() {
        return y;
    }

    @Override
    public int getWidth() {
        return 0;
    }

    @Override
    public int getHeight() {
        return 0;
    }

    @Override
    public void drag() {
        dx = x;
        dy = y;
    }

    @Override
    public void moveTo(int x, int y) {
        this.x = dx + x;
        this.y = dy + y;
    }

    @Override
    public void moveBy(int x, int y) {
        this.x += x;
        this.y += y;
    }

    @Override
    public void drop() {
        this.x = dx;
        this.y = dy;
    }

    @Override
    public boolean isInsideBounds(int x, int y) {
        return x > getX() && x < (getX() + getWidth()) &&
                y > getY() && y < (getY() + getHeight());
    }

    @Override
    public Color getColor() {
        return color;
    }

    @Override
    public void setColor(Color color) {
        this.color = color;
    }

    @Override
    public void select() {
        selected = true;
    }

    @Override
    public void unSelect() {
        selected = false;
    }

    @Override
    public boolean isSelected() {
        return selected;
    }

    void enableSelectionStyle(Graphics graphics) {
        graphics.setColor(Color.LIGHT_GRAY);

        Graphics2D g2 = (Graphics2D) graphics;
        float dash1[] = {2.0f};
        g2.setStroke(new BasicStroke(1.0f,
                BasicStroke.CAP_BUTT,
                BasicStroke.JOIN_MITER,
                2.0f, dash1, 0.0f));
    }

    void disableSelectionStyle(Graphics graphics) {
        graphics.setColor(color);
        Graphics2D g2 = (Graphics2D) graphics;
        g2.setStroke(new BasicStroke());
    }

    @Override
    public void paint(Graphics graphics) {
        if (isSelected()) {
            enableSelectionStyle(graphics);
        }
        else {
            disableSelectionStyle(graphics);
        }

        // ...
    }
}
View Code

  shapes/Circle.java

package memento.shapes;

import java.awt.*;

/**
 * @author GaoMing
 * @date 2021/7/25 - 20:57
 */
public class Circle extends BaseShape{
    private int radius;

    public Circle(int x, int y, int radius, Color color) {
        super(x, y, color);
        this.radius = radius;
    }

    @Override
    public int getWidth() {
        return radius * 2;
    }

    @Override
    public int getHeight() {
        return radius * 2;
    }

    @Override
    public void paint(Graphics graphics) {
        super.paint(graphics);
        graphics.drawOval(x, y, getWidth() - 1, getHeight() - 1);
    }
}

  shapes/Dot.java

package memento.shapes;

import java.awt.*;

/**
 * @author GaoMing
 * @date 2021/7/25 - 20:57
 */
public class Dot extends BaseShape{
    private final int DOT_SIZE = 3;

    public Dot(int x, int y, Color color) {
        super(x, y, color);
    }

    @Override
    public int getWidth() {
        return DOT_SIZE;
    }

    @Override
    public int getHeight() {
        return DOT_SIZE;
    }

    @Override
    public void paint(Graphics graphics) {
        super.paint(graphics);
        graphics.fillRect(x - 1, y - 1, getWidth(), getHeight());
    }
}

  shapes/Rectangle.java

package memento.shapes;

import java.awt.*;

/**
 * @author GaoMing
 * @date 2021/7/25 - 20:58
 */
public class Rectangle extends BaseShape{
    private int width;
    private int height;

    public Rectangle(int x, int y, int width, int height, Color color) {
        super(x, y, color);
        this.width = width;
        this.height = height;
    }

    @Override
    public int getWidth() {
        return width;
    }

    @Override
    public int getHeight() {
        return height;
    }

    @Override
    public void paint(Graphics graphics) {
        super.paint(graphics);
        graphics.drawRect(x, y, getWidth() - 1, getHeight() - 1);
    }
}

  shapes/CompoundShape.java

package memento.shapes;

import java.awt.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * @author GaoMing
 * @date 2021/7/25 - 20:59
 */
public class CompoundShape extends BaseShape{
    private List<Shape> children = new ArrayList<>();

    public CompoundShape(Shape... components) {
        super(0, 0, Color.BLACK);
        add(components);
    }

    public void add(Shape component) {
        children.add(component);
    }

    public void add(Shape... components) {
        children.addAll(Arrays.asList(components));
    }

    public void remove(Shape child) {
        children.remove(child);
    }

    public void remove(Shape... components) {
        children.removeAll(Arrays.asList(components));
    }

    public void clear() {
        children.clear();
    }

    @Override
    public int getX() {
        if (children.size() == 0) {
            return 0;
        }
        int x = children.get(0).getX();
        for (Shape child : children) {
            if (child.getX() < x) {
                x = child.getX();
            }
        }
        return x;
    }

    @Override
    public int getY() {
        if (children.size() == 0) {
            return 0;
        }
        int y = children.get(0).getY();
        for (Shape child : children) {
            if (child.getY() < y) {
                y = child.getY();
            }
        }
        return y;
    }

    @Override
    public int getWidth() {
        int maxWidth = 0;
        int x = getX();
        for (Shape child : children) {
            int childsRelativeX = child.getX() - x;
            int childWidth = childsRelativeX + child.getWidth();
            if (childWidth > maxWidth) {
                maxWidth = childWidth;
            }
        }
        return maxWidth;
    }

    @Override
    public int getHeight() {
        int maxHeight = 0;
        int y = getY();
        for (Shape child : children) {
            int childsRelativeY = child.getY() - y;
            int childHeight = childsRelativeY + child.getHeight();
            if (childHeight > maxHeight) {
                maxHeight = childHeight;
            }
        }
        return maxHeight;
    }

    @Override
    public void drag() {
        for (Shape child : children) {
            child.drag();
        }
    }

    @Override
    public void drop() {
        for (Shape child : children) {
            child.drop();
        }
    }

    @Override
    public void moveTo(int x, int y) {
        for (Shape child : children) {
            child.moveTo(x, y);
        }
    }

    @Override
    public void moveBy(int x, int y) {
        for (Shape child : children) {
            child.moveBy(x, y);
        }
    }

    @Override
    public boolean isInsideBounds(int x, int y) {
        for (Shape child : children) {
            if (child.isInsideBounds(x, y)) {
                return true;
            }
        }
        return false;
    }

    @Override
    public void setColor(Color color) {
        super.setColor(color);
        for (Shape child : children) {
            child.setColor(color);
        }
    }

    @Override
    public void unSelect() {
        super.unSelect();
        for (Shape child : children) {
            child.unSelect();
        }
    }

    public Shape getChildAt(int x, int y) {
        for (Shape child : children) {
            if (child.isInsideBounds(x, y)) {
                return child;
            }
        }
        return null;
    }

    public boolean selectChildAt(int x, int y) {
        Shape child = getChildAt(x,y);
        if (child != null) {
            child.select();
            return true;
        }
        return false;
    }

    public List<Shape> getSelected() {
        List<Shape> selected = new ArrayList<>();
        for (Shape child : children) {
            if (child.isSelected()) {
                selected.add(child);
            }
        }
        return selected;
    }

    @Override
    public void paint(Graphics graphics) {
        if (isSelected()) {
            enableSelectionStyle(graphics);
            graphics.drawRect(getX() - 1, getY() - 1, getWidth() + 1, getHeight() + 1);
            disableSelectionStyle(graphics);
        }

        for (Shape child : children) {
            child.paint(graphics);
        }
    }

}
View Code

  Demo.java: 初始化代码

package memento;

import memento.editor.Editor;
import memento.shapes.Circle;
import memento.shapes.CompoundShape;
import memento.shapes.Dot;
import memento.shapes.Rectangle;

import java.awt.*;

/**
 * @author GaoMing
 * @date 2021/7/25 - 20:47
 */
public class Demo {
    public static void main(String[] args) {
        Editor editor = new Editor();
        editor.loadShapes(
                new Circle(10, 10, 10, Color.BLUE),

                new CompoundShape(
                        new Circle(110, 110, 50, Color.RED),
                        new Dot(160, 160, Color.RED)
                ),

                new CompoundShape(
                        new Rectangle(250, 250, 100, 100, Color.GREEN),
                        new Dot(240, 240, Color.GREEN),
                        new Dot(240, 360, Color.GREEN),
                        new Dot(360, 360, Color.GREEN),
                        new Dot(360, 240, Color.GREEN)
                )
        );
    }
}

  运行结果    

 

  7. 与其余模式的关系

  • 能够同时使用命令模式和备忘录模式来实现 “撤销”。在这种状况下,命令用于对目标对象执行各类不一样的操做,备忘录用来保存一条命令执行前该对象的状态
  • 能够同时使用备忘录和迭代器模式来获取当前迭代器的状态,而且在须要的时候进行回滚
  • 有时候原型模式能够做为备忘录的一个简化版本,其条件是你须要在历史记录中存储的对象的状态比较简单,不须要连接其余外部资源,或者连接能够方便地重建

  8. 已知应用

  使用示例:备忘录的基本原则可经过序列化来实现,这在Java语言中很常见。尽管备忘录不是生成对象状态快照的惟一或最有效方法,但它能在保护原始对象的结构不暴露给其余对象的状况下保存对象状态的备份
  下面是核心 Java 程序库中该模式的一些示例:

  全部 java.io.Serializable 的实现均可以模拟备忘录  全部 javax.faces.component.StateHolder 的实现

相关文章
相关标签/搜索