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

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

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 Prototype pattern II. The State pattern 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 Memento pattern 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 Composite pattern 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

View Full Text

Details

  • File Type
    pdf
  • Upload Time
    -
  • Content Languages
    English
  • Upload User
    Anonymous/Not logged-in
  • File Pages
    13 Page
  • File Size
    -

Download

Channel Download Status
Express Download Enable

Copyright

We respect the copyrights and intellectual property rights of all users. All uploaded documents are either original works of the uploader or authorized works of the rightful owners.

  • Not to be reproduced or distributed without explicit permission.
  • Not used for commercial purposes outside of approved use cases.
  • Not used to infringe on the rights of the original creators.
  • If you believe any content infringes your copyright, please contact us immediately.

Support

For help with questions, suggestions, or problems, please contact us