(Optional) GUI and Graphics Case Study: Drawing with Polymorphism
(Optional) GUI and Graphics Case Study Drawing with Polymorphism
You may have noticed in the drawing program created in Exercise 8.1 (and modified in Exercise 9.1) that there are many similarities between the shape classes. Using inheritance, we can "factor out" the common features from all three classes and place them in a single shape superclass. We can then manipulate objects of all three shape types polymorphically using variables of the superclass type. Removing the redundancy in the code will result in a smaller, more flexible program that is easier to maintain.
GUI and Graphics Case Study Exercises
10.1 |
Modify the MyLine, MyOval and MyRectangle classes of Exercise 8.1 and Exercise 9.1 to create the class hierarchy in Fig. 10.17. Classes of the MyShape hierarchy should be "smart" shape classes that know how to draw themselves (if provided with a Graphics object that tells them where to draw). Once the program creates an object from this hierarchy, it can manipulate it polymorphically for the rest of its lifetime as a MyShape. Figure 10.17. MyShape hierarchy. (This item is displayed on page 497 in the print version) In your solution, class MyShape in Fig. 10.17 must be abstract. Since MyShape represents any shape in general, you cannot implement a draw method without knowing exactly what shape it is. The data representing the coordinates and color of the shapes in the hierarchy should be declared as private members of class MyShape. In addition to the common data, class MyShape should declare the following methods:
To ensure proper encapsulation, all data in class MyShape must be private. This requires declaring proper set and get methods to manipulate the data. Class MyLine should provide a no-argument constructor and a constructor with arguments for the coordinates and color. Classes MyOval and MyRect should provide a no-argument constructor and a constructor with arguments for the coordinates, color and determining whether the shape is filled. The no-argument constructor should, in addition to setting the default values, set the shape to be an unfilled shape. You can draw lines, rectangles and ovals if you know two points in space. Lines require x1, y1, x2 and y2 coordinates. The drawLine method of the Graphics class will connect the two points supplied with a line. If you have the same four coordinate values (x1, y1, x2 and y2) for ovals and rectangles, you can calculate the four arguments needed to draw them. Each requires an upper-left x-coordinate value (the smaller of the two x-coordinate values), an upper-left y-coordinate value (the smaller of the two y coordinate values), a width (the absolute value of the difference between the two x-coordinate values) and a height (the absolute value of the difference between the two y-coordinate values). Rectangles and ovals should also have a filled flag that determines whether to draw the shape as a filled shape. There should be no MyLine, MyOval or MyRectangle variables in the programonly MyShape variables that contain references to MyLine, MyOval and MyRectangle objects. The program should generate random shapes and store them in an array of type MyShape. Method paintComponent should walk through the MyShape array and draw every shape (i.e., polymorphically calling every shape's draw method). Allow the user to specify (via an input dialog) the number of shapes to generate. The program will then generate and display the shapes along with a status bar that informs the user how many of each shape were created. |
10.2 |
(Drawing Application Modification) In Exercise 10.1, you created a MyShape hierarchy in which classes MyLine, MyOval and MyRectangle extend MyShape directly. If your hierarchy was properly designed, you should be able to see the similarities between the MyOval and MyRectangle classes. Redesign and reimplement the code for the MyOval and MyRectangle classes to "factor out" the common features into the abstract class MyBoundedShape to produce the hierarchy in Fig. 10.18. Figure 10.18. MyShape hierarchy with MyBoundedShape. Class MyBoundedShape should declare two constructors that mimic the constructors of class MyShape, only with an added parameter to set whether the shape is filled. Class MyBoundedShape should also declare get and set methods for manipulating the filled flag and methods that calculate the upper-left x- coordinate, upper-left y-coordinate, width and height. Remember, the values needed to draw an oval or a rectangle can be calculated from two (x, y) coordinates. If designed properly, the new MyOval and MyRectangle classes should each have two constructors and a draw method. |