- A Classic Example: Using Memento for Undo
- Memento Durability
- Persisting Mementos Across Sessions
- Summary
Persisting Mementos Across Sessions
A session occurs when a user runs a program, conducts transactions in the program, and exits. Suppose that your users want to be able to save a simulation in one session and restore it in another session. This ability is a matter normally referred to as persistent storage. Persistent storage fulfills the intent of the Memento pattern and is a natural extension to the undo functionality you have already implemented.
Suppose that you subclass the Visualization class with a Visualization2 class that has a menu bar with a File menu with Save As... and Restore From... items:
package com.oozinoz.visualization; import javax.swing.*; import com.oozinoz.ui.SwingFacade; import com.oozinoz.ui.UI;
public class Visualization2 extends Visualization { public Visualization2(UI ui) { super(ui); } public JMenuBar menus() { JMenuBar menuBar = new JMenuBar(); JMenu menu = new JMenu("File"); menuBar.add(menu); JMenuItem menuItem = new JMenuItem("Save As..."); menuItem.addActionListener(mediator.saveAction()); menu.add(menuItem); menuItem = new JMenuItem("Restore From..."); menuItem.addActionListener( mediator.restoreAction()); menu.add(menuItem); return menuBar; } public static void main(String[] args) { Visualization2 panel = new Visualization2(UI.NORMAL); JFrame frame = SwingFacade.launch( panel, "Operational Model"); frame.setJMenuBar(panel.menus()); frame.setVisible(true); } }
This code requires the addition of saveAction() and restoreAction() methods to the VisMediator class. The MenuItem objects cause these actions to be called when the menu is selected. When the Visualization2 class runs, the GUI appears as in Figure 19.7. An easy way to store an object, such as the factory model’s topmost configuration, is to serialize it. The code for the saveAction() method in the VisMediator class might appear as follows:
Figure 19.7 The addition of a File menu lets a user save a memento that the application can later restore from.
public ActionListener saveAction() { return new ActionListener() { public void actionPerformed(ActionEvent e) { try {
VisMediator.this.save((Component)e.getSource()); } catch (Exception ex) { System.out.println( "Failed save: " + ex.getMessage()); } }}; } public void save(Component source) throws Exception { JFileChooser dialog = new JFileChooser(); dialog.showSaveDialog(source); if (dialog.getSelectedFile() == null) return;
FileOutputStream out = null; ObjectOutputStream s = null; try { out = new FileOutputStream(dialog.getSelectedFile()); s = new ObjectOutputStream(out); s.writeObject(factoryModel.getLocations()); } finally { if (s != null) s.close(); } }
Challenge 19.4
Write the code for the restoreAction() method of the VisMediator class.
A solution appears on page 402.
Design Patterns states the intent of the Memento pattern as, “Without violating encapsulation, capture and externalize an object’s internal state so that the object can be restored to this state later.”
Challenge 19.5
In this case, we used Java serialization to write to a file in binary format. Suppose that we had written it to XML format (textual) instead. Write a short statement of whether, in your opinion, saving a memento in textual form would violate encapsulation.
A solution appears on page 403.
You should understand what a developer means in saying that he or she creates mementos by storing an object’s data via serialization or via writing to an XML file. That’s the point of design patterns: By using a common vocabulary, we can readily discuss design concepts and their application.