September 1, 2014
Hot Topics:
RSS RSS feed Download our iPhone app

Working With Design Patterns: Memento

  • January 10, 2008
  • By Jeff Langr
  • Send Email »
  • More Articles »

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;
   }
}




Page 2 of 3



Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Sitemap | Contact Us

Rocket Fuel