Design Patterns: Prototype, State, Composite, Memento Let’s start by considering the Outline for Lecture 24 CanvasEditor as we had it at the end of the last class. I. The II. The Recall that when a button was clicked, the III. The Composite button’s custom ActionListener was pattern invoked, and it set the current figure to the IV. The proper type: rectButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent ae) { canvasEditor.setCurrentFigure (new Rect(0,0, 60, 40)); } });

The setCurrentFigure message was received by the canvasEditor object. Let’s take a look at the code for it.

public class CanvasEditor implements MouseListener { private Figure currentFigure; public CanvasEditor(Figure initialFigure) { this.currentFigure = initialFigure; }

public void setCurrentFigure(Figure newFigure) { currentFigure = newFigure; }

public void mouseClicked(MouseEvent e) { Figure newFigure = ... a new figure based on currentFigure... ; ((DrawingCanvas) e.getSource()). addFigure(newFigure); }

Lecture 24 Object-Oriented Languages and Systems 1

public void mousePressed(MouseEvent e) {} public void mouseReleased(MouseEvent e) {} public void mouseEntered(MouseEvent e) {} public void mouseExited(MouseEvent e) {} }

Notice that we haven’t said how to draw a new figure based on the current figure.

Prototype [Skrien §8.5] How shall we draw this figure? Can we use the currentFigure object?

Can we use a constructor to create it?

Should we test which kind of figure that we need?

if( currentFigure instanceof Ellipse ) newFigure = new Ellipse(...); else if( currentFigure instanceof Rect ) newFigure = new Rect(...); else newFigure = new Square(...);

Of course not!

Instead, we can just clone the current object. This makes use of Java’s Cloneable interface.

By implementing Cloneable , a class allows field-by-field copies to be made of its instances.

This allows the Figure referred to by currentFigure to act as a prototype for the figure to be created. Here is the code.

CSC/ECE 517 Lecture Notes © 2007 Edward F. Gehringer 2

public Object clone() { try { return super.clone(); } catch (CloneNotSupportedException e) { // This should never happen e.printStackTrace(); return null; } }

Why does the method call super.clone ?

What class do we place this definition in?

How do we use this method to create “ ... a new figure based on currentFigure... ?

public void mouseClicked(MouseEvent e) { Figure newFigure = (Figure) currentFigure.clone(); newFigure.setCenter(e.getX(), e.getY()); ((DrawingCanvas) e.getSource()) addFigure(newFigure); }

This is an instance of the Prototype pattern.

Prototype

Intent: Specify the kinds of objects to create using a prototypical instance, and create new objects by copying this prototype.

Problem: Customized objects must be created, but we do not know their class or any details of how to create them.

Solution: Each class that might have to create an object has a prototypical object. A creation-initiating object is invoked, and it creates objects by asking one of the prototypical objects to make a copy of itself.

Lecture 24 Object-Oriented Languages and Systems 3

Implementation: Each class that is going to create an object must have a prototypical object. The parent class implements the Cloneable interface. Then the creation-initiating object clones itself, producing an object of the correct class. State [Skrien §8.6] We’ve been talking about bad uses of case statements in programs. Another way in which case statements are sometimes used is to implement finite-state machines.

Here’s an example.

Table form of FSM: State/Input input1 input2 input3 input4 State1 (different actions for each State2 combination of state and State3 input)

while (state != Final) { switch (state) { case State1: if (input == input1)action11; else if (input == input2) action12; else if (input == input3) action13; else if (input == input4) action14; break; case State2: if (input == input1)action21; else if (input == input2) action22; else if (input == input3) action23; else if (input == input4) action24; break; ... default : System.out.println(" Invalid state: " + state); } }

How can we do this in a more o-o fashion? Hint: We can make State an interface!

CSC/ECE 517 Lecture Notes © 2007 Edward F. Gehringer 4

public interface

How should the State s be defined?

How should these methods be implemented for each state?

Let’s see how this approach could help our drawing program.

So far, our application just creates figures and puts them at different places on the canvas. Once positioned, they stay in the same place forever.

We’d like to enhance the app to allow the figures to move. This requires adding a selection tool to the menu.

When the selection tool is chosen and (a) the user clicks the mouse button inside an unselected figure, then that figure becomes the only selected figure. (b) the user clicks the mouse button inside a selected figure or outside all the figures, nothing changes. (c) the user presses the mouse inside an unselected figure and drags , then that figure becomes the only selected figure and is dragged along with the mouse. (d) the user presses the mouse inside a selected figure and drags , then that figure and all other currently selected figures are dragged with the mouse.

Lecture 24 Object-Oriented Languages and Systems 5

(e) the user presses the mouse outside all figures and drags the mouse, a selection area is outlined and all figures intersecting the selection area become the selected figures.

This is pretty standard behavior for drawing applications. It requires a major change to our application.

Until now, we were able to ignore mouse presses, drags, and releases. However, if the selection tool is chosen, they will have to be tracked and various actions will have to be implemented.

We could do this with conditionals: public void mouseClicked(MouseEvent e){ if currentTool = selection { drawing.getFigureContaining( (e.getX(), e.getY()); } else { Figure newFigure = (Figure) currentFigure.clone(); newFigure.setCenter(e.getX(), e.getY()); ((DrawingCanvas) e.getSource()).addFigure (newFigure); } }

But do we want to? What can we do instead?

We can use the State pattern!

State

Intent: Allow an object to alter its behavior when its internal state changes. The object will appear to change its class.

Problem: A monolithic object's behavior is a function of its state, and it must change its behavior at run-time depending on that state. Or, an application is characterized by large and numerous case statements that vector flow of control based on the state of the application.

CSC/ECE 517 Lecture Notes © 2007 Edward F. Gehringer 6

Solution: Define a set of State objects. Defer the implementation of the different methods to the State objects. The client changes its state from time to time.

Implementation: • Define a “context” class to present a single interface to the outside world. • Define a State abstract base class. • Represent the different “states” of the state machine as derived classes of the State base class. • Define state-specific behavior in the appropriate State derived classes. • Maintain a pointer to the current “state” in the “context” class. • To change the state of the state machine, change the current “state” pointer.

With the State pattern, the object needing different behavior will maintain a reference to another object representing its state.

Instead of having the mouseClicked method in the CanvasEditor , there are now multiple mouseClicked methods, located in the Tool classes. Here’s the method in CreationTool :

public void mouseClicked(MouseEvent e){ Figure newFigure = (Figure) myFigure.clone(); newFigure.moveTo(e.getX() - newFigure.getBoundingRect().width / 2, e.getY() - newFigure.getBoundingRect().height / 2); DrawingCanvas canvas = (DrawingCanvas) e.getSource(); canvas.addFigure(newFigure); canvas.unselectAll(); canvas.selectFigure(newFigure); }

Here’s the method in SelectionTool :

Lecture 24 Object-Oriented Languages and Systems 7 public void mouseClicked(MouseEvent e) { DrawingCanvas canvas = (DrawingCanvas) e.getSource(); Figure figure = canvas.getFigureContaining (e.getX(), e.getY()); pressedInFigure = (figure != null); if (pressedInFigure && ! figure.isSelected()) canvas.unselectAll(); if (pressedInFigure) figure.setSelected(true); origin.x = e.getX(); origin.y = e.getY(); }

Composite [Skrien §8.7] Next, we need to allow users to group figures together to make a “composite” figure, which can be manipulated as a single figure.

Our Drawing class stores all its figures in an ArrayList named “figures ”. We could create a separate ArrayList for each group.

That is, to implement the "Group" menu item action, we can just

• remove all the selected figures from figures , • put those selected figures into a new ArrayList , and • add that ArrayList to figures .

The problem is that the Drawing class assumes that only Figure objects are in ArrayList s. So all drawing methods will have to be rewritten similarly to this:

if( figures.get(i) instanceof ArrayList) ...do the desired processing on the group... else ...do the desired processing on the figure...

Things would get worse if a group contained another group.

The solves this. It has

CSC/ECE 517 Lecture Notes © 2007 Edward F. Gehringer 8

• one or more “leaf” classes, representing individual objects, and • a “composite” class, representing collections of objects.

Both of these are subclasses of a component class.

A client can refer to components without knowing whether they are composites or leaves.

In our drawing program, which are the composites and which are the leaves?

Here is a UML diagram:

Let’s take a look at a sample method, drawShape , in each of the classes. Which class is each in? public void drawShape(Graphics g){ Rectangle rect = getBoundingRect();

Lecture 24 Object-Oriented Languages and Systems 9

g.drawRect(rect.x, rect.y, rect.width, rect.height); } public void drawShape(Graphics g) { for (Iterator

it = children.iterator(); it.hasNext();) { it.next().drawShape(g); } }

public void drawShape(Graphics g) { Rectangle rect = getBoundingRect(); g.drawOval(rect.x, rect.y, rect.width, rect.height); }

Composite

Intent: Allow clients to treat individual objects and compositions of objects uniformly. Problem: The application needs to manipulate a hierarchical collection of “primitive” and “composite” objects. Primitive objects are processed one way, and composite objects are handled differently. It is inelegant to query the “type” of each object before processing it. Solution: Define an abstract base class (Component) that specifies the behavior that needs to be exercised uniformly across all primitive and composite objects. Make the Primitive and Composite classes subclasses of the Component class.

Memento A standard feature of an editor is the ability to undo the most recent changes that the user has made.

Let’s add this functionality to our drawing application.

We’ll do this by adding an “undo” stack, which holds previous states of the canvas.

CSC/ECE 517 Lecture Notes © 2007 Edward F. Gehringer 10

The top of the stack always corresponds to the current state of the canvas.

Now, what two things should we do when a change is undone?

We could make the DrawingCanvas handle undoing and redoing. But this gives it a lot of extra responsibility. Is there a more elegant way?

The Memento pattern solves this problem. It allows an external class to handle the states, but doesn’t let this external class manipulate them in any way.

Here is a description of Memento.

Memento Intent: Without violating encapsulation, capture and externalize an object’s internal state so that the object can be returned to this state later. Problem: We need to restore an object to its previous state. Solution: Use an Originator, which creates the Mementos (states) and a Caretaker, which performs safekeeping of the Mementos. Implementation: The client requests a Memento from the Originator when it needs to checkpoint the source object’s state. The source object sets the Memento to a characterization of its state. The Caretaker preserves the Memento, but only the Originator can store and retrieve information from the Memento (the Memento is "opaque" to the client and all other objects). If the client subsequently needs to “roll back” the source object’s state, it hands the Memento back to the Originator for reinstatement.

Let’s take a look at an outline of the code for the undo-redo handler. More details appear in the book.

public class UndoRedoHandler { private CanvasStateStack undoStack, redoStack; private DrawingCanvas canvas;

Lecture 24 Object-Oriented Languages and Systems 11

public UndoRedoHandler(DrawingCanvas canvas) { undoStack = new CanvasStateStack(); redoStack = new CanvasStateStack(); this.canvas = canvas; // Store the initial state of the canvas on // the undo stack undoStack.push(canvas.createMemento()); }

... public void undo() { if( undoStack.size() == 1) return; // Only current state is on stack

DrawingCanvas.State canvasState = undoStack.pop(); redoStack.push(canvasState); canvas.restoreState(undoStack.peek()); }

public void redo() { if( redoStack.isEmpty()) return;

DrawingCanvas.State canvasState = redoStack.pop(); undoStack.push(canvasState); canvas.restoreState(canvasState); } }

We only need to add two methods to the DrawingCanvas class. What are they?

Here is a UML that shows what happens when a change is undone.

CSC/ECE 517 Lecture Notes © 2007 Edward F. Gehringer 12

1. The ActionListener for the Undo menu item signals the UndoRedoHandler to undo. 2. The UndoRedoHandler then a. extracts the State to be restored from its undo stack and b. signals the DrawingCanvas to restore its state to that State . 3. Since the internals of the State object are private, the DrawingCanvas cannot access them, but it can ask the State object to restore the canvas’s state for it.

Lecture 24 Object-Oriented Languages and Systems 13