Working With Design Patterns: Memento, Page 2
When you undo a command, it needs to reset the state of the PathCanvas to a prior point in time. A stored Memento object represents this prior point. The method setMemento updates the state of the PathCanvas object.
Listing 4: PathCanvas.
import java.awt.*;
import java.awt.geom.*;
import java.util.*;
import java.util.List;
public class PathCanvas extends Observable implements
MementoOriginator, Displayable {
private List<ColoredPath> paths =
new ArrayList<ColoredPath>();
public List<ColoredPath> paths() {
return paths;
}
public void add(ColoredPath path) {
paths.add(path);
changed();
}
public void displayOn(Graphics2D graphics) {
for (ColoredPath path: paths) {
Area polygon = new Area(path.getGeneralPath());
graphics.setColor(path.getColor());
graphics.fill(polygon);
}
}
public Memento getMemento() {
List<ColoredPath> pathCopies =
new ArrayList<ColoredPath>();
pathCopies.addAll(paths);
return new Memento(pathCopies);
}
@Override
public void setMemento(Memento memento) {
paths.clear();
paths.addAll(memento.getPaths());
changed();
}
private void changed() {
setChanged();
notifyObservers();
}
}
I created the MementoOriginator interface not out of necessity, but to reinforce the class names used in the Design Patterns book. The interface is simply:
public interface MementoOriginator {
Memento getMemento();
void setMemento(Memento memento);
}
Listing 5: Memento.
import java.util.*;
public class Memento {
private List<ColoredPath> paths;
public Memento(List<ColoredPath> paths) {
this.paths = paths;
}
public List<ColoredPath> getPaths() {
return paths;
}
}
The most involved piece of the puzzle is the set of commands themselves. I implemented TriangleCommand and SquareCommand to demonstrate drawing a couple different shapes. Because each command needs to support being executed, undone, and redone, I was able to move some commonality into a superclass AbstractCommand (see Listing 6).
Listing 6: AbstractCommand.
import java.awt.*;
import java.util.*;
import model.*;
import model.PathCanvas;
import commandframework.*;
abstract public class AbstractCommand implements Command {
private Memento memento;
private Random random = new Random();
protected double width;
protected double height;
protected PathCanvas canvas;
protected Color color;
public AbstractCommand() {
}
public AbstractCommand(PathCanvas canvas, double width,
double height, Color color) {
this.width = width;
this.height = height;
this.canvas = canvas;
this.color = color;
}
public void execute() {
this.memento = canvas.getMemento();
transform();
}
abstract protected void transform();
public void undo() {
Memento redoMemento = canvas.getMemento();
canvas.setMemento(memento);
memento = redoMemento;
}
public void redo() {
Memento undoMemento = canvas.getMemento();
canvas.setMemento(memento);
memento = undoMemento;
}
protected double random(double max) {
return random.nextDouble() * max;
}
}
