Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs
Historically, application frameworks (for example, MacApp framework) have based the design of the undo/redo mechanism around the Command pattern. And that's what we're going to do as well. We'll discuss the Command pattern and describe how it supports the design of undo/redo systems. We'll then examine Java's support for the pattern and see how Swing's undo package adds the missing functionality, providing you with a complete undo/redo mechanism.
Undo allows users to correct their mistakes and also to try out different aspects of the application without risk of repercussions.
At minimum, an undo/redo mechanism should provide users with the ability to:
In order to design such a mechanism, we must treat the user's operations as individual atomic actions (self-contained actions that know how to undo/redo their effect on the application state) that should be stored for undo or redo later on. We can fulfill these requirements by using design patterns, specifically the Command pattern. If you are already familiar with the design patterns (specifically the Command pattern and how Java supports it), you can skip the next three sections and move right to "The undo/redo mechanism in Swing."
You may be wondering why I'm discussing design patterns in an article devoted to undo/redo mechanisms. It's really quite simple. In addition to presenting you with the technical implementation issues, I think it's important that you understand the design essentials of an undo/redo systems.
According to Design Patterns: Elements of Reusable Object-Oriented Software by the now infamous Gang of Four (see Resources for more information), the essential parts of any pattern are:
A number of different patterns exist, but we're concerned only with the one that addresses undo/redo capabilities: the Command pattern.
The Command pattern
Once again, according to Design Patterns, the purpose of the Command pattern is to:
Encapsulate a request as an object, thereby letting you parameterize clients with different requests, queue or log requests, and support undoable operations.
Let's see how this works.