> 文章列表 > 备忘录设计模式(Memento Pattern)[论点:概念、组成角色、示例代码、框架中的运用、适用场景]

备忘录设计模式(Memento Pattern)[论点:概念、组成角色、示例代码、框架中的运用、适用场景]

备忘录设计模式(Memento Pattern)[论点:概念、组成角色、示例代码、框架中的运用、适用场景]

文章目录

  • 概念
  • 组成角色
  • 示例代码
  • 框架中的运用
  • 适用场景

概念

备忘录模式(Memento Pattern)是一种行为型设计模式,主要用于保存对象的内部状态,以便在需要时恢复到先前的状态。这种模式有助于实现撤销、恢复或回滚操作,同时保持对象封装性。

组成角色

  1. 发起人(Originator):负责创建一个备忘录,用于存储当前对象的内部状态,并在需要时恢复到先前的状态。
  2. 备忘录(Memento):存储发起人对象的内部状态。备忘录应该只能被发起人访问和修改。
  3. 管理者(Caretaker):负责存储备忘录。管理者不应修改或直接访问备忘录的内容。

示例代码

        在此示例中,BankAccount(Originator)类表示一个简单的银行账户,支持存款和取款操作。每次执行操作时,我们都将当前余额保存到一个BankAccountMemento(Memento)对象中,并将其添加到BankAccountCaretaker对象的列表中。当需要执行撤销操作时,我们可以通过BankAccountCaretaker对象获取相应的BankAccountMemento对象,并将BankAccount的余额恢复到先前的状态。

package design.pattern.Memento;import java.util.Stack;// 定义一个可撤销操作的接口
interface UndoableOperation {void deposit(double amount);void withdraw(double amount);void undo();void redo();double getBalance();
}// Memento 类,存储银行账户的余额
class BankAccountMemento {private double balance;public BankAccountMemento(double balance) {this.balance = balance;}public double getBalance() {return balance;}
}// Originator 类,实现了 UndoableOperation 接口
class BankAccount implements UndoableOperation {private double balance;// 用来存储撤销操作的栈private Stack<BankAccountMemento> undoStack = new Stack<>();// 用来存储重做操作的栈private Stack<BankAccountMemento> redoStack = new Stack<>();public BankAccount(double balance) {this.balance = balance;undoStack.push(saveToMemento());}@Overridepublic void deposit(double amount) {redoStack.clear();balance += amount;undoStack.push(saveToMemento());}@Overridepublic void withdraw(double amount) {redoStack.clear();balance -= amount;undoStack.push(saveToMemento());}@Overridepublic double getBalance() {return balance;}private BankAccountMemento saveToMemento() {return new BankAccountMemento(balance);}private void restoreFromMemento(BankAccountMemento memento) {balance = memento.getBalance();}@Overridepublic void undo() {if (!undoStack.isEmpty()) {redoStack.push(undoStack.pop());if (!undoStack.isEmpty()) {restoreFromMemento(undoStack.peek());}}}@Overridepublic void redo() {if (!redoStack.isEmpty()) {BankAccountMemento memento = redoStack.pop();restoreFromMemento(memento);undoStack.push(memento);}}
}//扮演Caretaker的角色
public class MementoPatternDemo {public static void main(String[] args) {// 创建一个实现了 UndoableOperation 接口的 BankAccount 对象,开始操作时金额为1000UndoableOperation bankAccount = new BankAccount(1000.0);// 执行存款操作bankAccount.deposit(500);System.out.println("Current balance: " + ((BankAccount) bankAccount).getBalance());// 执行取款操作bankAccount.withdraw(200);System.out.println("Current balance: " + ((BankAccount) bankAccount).getBalance());// 执行撤销操作bankAccount.undo();System.out.println("Undo last change: " + ((BankAccount) bankAccount).getBalance());// 再次执行撤销操作bankAccount.undo();System.out.println("Undo two changes: " + ((BankAccount) bankAccount).getBalance());// 执行重做操作bankAccount.redo();System.out.println("Redo last change: " + ((BankAccount) bankAccount).getBalance());//*             (存500)      (取200)       (撤销一次操作)       (撤销两次操作)       (执行重做操作)         *////*金额变化:1000 ------> 1500 ------> 1300 ------------> 1500 ------------> 1000 ------------>  1500   *//}
}

框架中的运用

Swing库中的javax.swing.undo包,它提供了一种在Swing应用程序中实现撤销和重做功能的通用框架。

首先,我们需要创建一个简单的Swing应用程序,包含一个JTextArea组件,并添加撤销和重做按钮。

import javax.swing.*;
import javax.swing.undo.CannotRedoException;
import javax.swing.undo.CannotUndoException;
import javax.swing.undo.UndoManager;
import java.awt.*;public class SwingMementoDemo {public static void main(String[] args) {//在这个示例中,我们使用了Swing库中的UndoManager类,它实际上是一个Caretaker角色的实现。UndoManager类维护一个存储UndoableEdit对象(表示可撤销的编辑操作)的栈。UndoableEdit是一个接口,表示一个可撤销和重做的编辑操作,它的实现类充当了Memento角色。JFrame frame = new JFrame("Swing Memento Demo");frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);frame.setSize(400, 300);JTextArea textArea = new JTextArea();JScrollPane scrollPane = new JScrollPane(textArea);frame.add(scrollPane, BorderLayout.CENTER);// Set up UndoManagerUndoManager undoManager = new UndoManager();textArea.getDocument().addUndoableEditListener(undoManager);// Set up buttonsJPanel buttonPanel = new JPanel();JButton undoButton = new JButton("Undo");JButton redoButton = new JButton("Redo");buttonPanel.add(undoButton);buttonPanel.add(redoButton);frame.add(buttonPanel, BorderLayout.NORTH);// Set up button actionsundoButton.addActionListener(e -> {try {if (undoManager.canUndo()) {undoManager.undo();}} catch (CannotUndoException ex) {ex.printStackTrace();}});redoButton.addActionListener(e -> {try {if (undoManager.canRedo()) {undoManager.redo();}} catch (CannotRedoException ex) {ex.printStackTrace();}});frame.setVisible(true);}
}

运行代码
可以在窗口中进行撤销和重做操作

备忘录设计模式(Memento Pattern)[论点:概念、组成角色、示例代码、框架中的运用、适用场景]

适用场景

  1. 需要实现撤销(Undo)和重做(Redo)操作:在文本编辑器、图像编辑器或数据库事务中,用户可能希望撤销或重做先前的操作。使用备忘录模式,可以保存对象的状态,然后在需要时恢复到特定的状态。
  2. 需要备份和恢复状态:在某些情况下,可能需要在某个时间点创建对象状态的快照,并在将来的某个时刻将对象恢复到该状态。例如,在游戏中,玩家可能希望保存游戏进度并在以后继续游戏。
  3. 需要限制对象状态的直接访问:如果希望对外部对象隐藏某个对象的内部状态,可以使用备忘录模式。这样,外部对象无法直接访问或修改对象的内部状态,只能通过Originator提供的接口与其状态进行交互。
  4. 需要在不违反封装原则的前提下,暂存对象的内部状态:备忘录模式允许对象在不暴露其实现细节的情况下,保存和恢复其内部状态。这符合封装原则,有助于保持代码的整洁和易于维护。