6.170 Laboratory in Software Engineering
Spring 2000
Problem Set 4: Type Hierarchies
Due: March 2, 2000
Handout 8

Standard Guidelines

To do this assignment as efficiently as possible, and to derive the most benefit, we recommend that you: To hand your solution in, follow the standard instructions, which state in part:
Each assignment should be handed in as hardcopy to your TA or to the course secretary (Kincade Dunn, NE43-529) by 4:30 PM on its due date. It is usually most convenient to give the assignment to your TA at the end of class on that day. Additionally, the source and compiled code for each problem set should be made available on Athena so your TA can test your program.
You should put your solution to this problem set in ~/6.170/ps4.
See the general information sheet (handout 1) for more detail

Purpose

This problem set concerns using subtyping for object substitution and subclassing for code reuse.  It will also help you gain familiarity with Graphical User Interface (GUI) programming using the Java Swing package.  You will extend a given abstract Java class to implement a Java interface.  This will produce another abstract class.  You will further extend the new abstract class to produce a hierarchy of concrete classes.  Finally, you will test these classes.  This will give you an opportunity to think about testing type hierarchies and GUI programs.
 

Background

The class hierarchy you are going to work with in this problem set is shown in the figure below.  Those rectangles with solid borders represent Java classes.  Among these rectangles, the two that are shadowed represent abstract classes.  The rectangle with dashed borders represents a Java interface.

FigureThing provides an abstraction for objects that can be cloned and drawn in a window.   The specification for FigureThing can be found in Appendix A.  Each FigureThing object consists of a set of properties: location, color, shape, and size.  However, merely drawing objects in a window is not very interesting.  Therefore, you will extend FigureThing to AnimatedThing so that it supports the Animatible interface.  The specifications for AnimatedThing and the Animatible interface can be found in Appendix B and Appendix C respectively.  AnimatedThing objects differ from FigureThing objects in that the former have an additional property, namely velocity, and support the step method defined in the Animatible interface.

Both FigureThing and AnimatedThing are abstract classes.  Therefore, you cannot instantiate them.  However, from AnimatedThing, there are two levels of concrete subclasses, which can be instantiated.  The direct subclasses of AnimatedThing consist of RectangleThing and OvalThing.  The second level subclasses consist of SquareThing and CircleThing.  Since a square is also a rectangle, it is natural for SquareThing to be implemented as a subclass of RectangleThing.  The same holds true between CircleThing and OvalThing.
 

Preparation

A small GUI program is provided for you to try run your program.  You should copy all the files in /mit/6.170/src/ps4/ to your working directory, which should be ~/6.170/ps4 on Athena.  There are 15 files in total.  These files include the GUI program as well as files for classes in the FigureThing hierarchy.
 

A sample screen shot of the GUI program is shown on the left.  The appearance of the window may vary slightly from one window environment to another window environment.  The entry point for the program is defined in ps4.java.  It creates a window and displays it on the screen.  The features and behavior of the window are defined in MainFrame.java.  The window contains a menu bar.  Objects in the FigureThing hierarchy are created from the File|New menu of the window.  Besides a menu bar, the window also contains a panel whose definition can be found in MainPanel.java.  Objects created from the File|New menu are added to the panel and can be manipulated inside.  Instructions about the use of the panel can be obtained from the Help|About dialog box.

When you implement the classes in the FigureThing hierarchy, you will come across objects of type Point, Dimension, Rectangle, Color, and Graphics.  These are standard Java classes and their documentation can be found at http://www.javasoft.com/products/jdk/1.2/docs/api/index.html .  The use of Point, Dimension, Rectangle, and Color are straight-forward.  To draw on the screen, you have to manipulate a Graphics object.

In order to manage multiple windows that can overlap with each other and can be resized, moved, and iconized by users, most window environments do not allow applications to draw directly on the screen.  Instead, each application draws on a graphics context provided by the window environment and the window environment maps the graphics context onto the screen.  In Java, a graphics context is an object of type Graphics.  (In the version of Java you are using, it is actually an object of type Graphics2D, which is derived from Graphics.  But to maintain compatibility with older versions of Java, graphics contexts are still passed around as objects of type Graphics.  Therefore, if you need to use a graphics context as a Graphics2D object, you need to down cast it from Graphics first.)  You will need to draw on a graphics context when you implement the abstract method draw in FigureThing in its subclasses.  The graphic context is passed to draw as its argument.  To draw on it, all you need to do is to call some methods defined in Graphics or Graphics2D on it.  Examples on manipulating graphics contexts can be found in Chapter 14 of the Beginning Java 2 book.

In general, when writing a GUI application, you will have to deal with multiple coordinate systems.  This is explained in Chapter 14 of the Beginning Java 2 book as well.  However, in this problem set, you will be drawing inside the MainPanel only.  Therefore, you will only deal with the coordinate system of the panel.  The origin of the panel is located at its upper left corner.  The positive x axis runs from left to right and the positive y axis runs from top to bottom.  All the coordinates you are going to work with are expressed in this coordinate system.

If you look at the specification of FigureThing, you will notice that the term "bounding rectangle" appears in several places.  The bounding rectangle of a figure is the smallest rectangle that aligns with the current coordinate system and completely encloses the figure.  In this problem set, you are only expected to draw figures aligned with the coordinate system of MainPanel, i.e. you do not need to draw slanted figures.  Therefore, the bounding rectangles of your rectangles and squares will be the same as the rectangles and the squares themselves.  Those of your ovals and circles are illustrated below.

Problem 1: Implementing AnimatedThing

In this problem you will implement AnimatedThing by extending FigureThing to support the Animatible interface.  The full definition of FigureThing can be found in the FigureThing.java file.  The specification and partial definition of AnimatedThing can be found in the AnimatedThing.java file.  Animatible is defined in Animatible.java.
After you have finished the implementation of AnimatedThing, you can try compile the GUI program to see if you have made any compile-time errors in AnimatedThing.  Here are the steps to do so:
  1. Make sure that all your ps4 files are in your ~/6.170/ps4 directory.
  2. Go to your ~/6.170 directory.
  3. At the Athena prompt, type: javac ps4/ps4.java
  4. If there is no error, you can try run the program from your ~/6.170 directory.  At the Athena prompt, type: java ps4.ps4
  5. If there are compile-time errors, make corrections to your AnimatedThing.java file,  go into your ps4 directory,  type:  make clean at the prompt, and start again from step 2 above.
If you run the program, you will find that you cannot create any objects from the File|New menu.  This is because the code that creates such objects has been commented out.  You will un-comment them after you have implemented the subclasses of AnimatedThing. 

Problem 2: Extending AnimatedThing

In this problem you will extend AnimatedThing to produce the concrete classes: RectangleThing and OvalThing.  Partial definitions of the classes can be found in RectangleThing.java and OvalThing.java.
To execute your implementation:
  1. Find towards the end of the MainFrame.java file the two lines of code where RectangleThing objects and OvalThing objects are created.  These lines have been commented out.  Un-comment them.
  2. Go to your ~/6.170/ps4 directory and type:  make clean at the prompt.
  3. Go to your ~/6.170 directory.
  4. At the Athena prompt, type: javac ps4/ps4.java
  5. If there is no error, you can try run the program from your ~/6.170 directory.  Type: java ps4.ps4 at the prompt.  See if you can create new Rectangle and Oval objects from the File|New menu and see if you can animate, move, and resize them.
  6. If there are compile-time errors, make corrections to your RectangleThing.java and OvalThing.java files and start again from step 2 above.

Problem 3: Extending RectangleThing and OvalThing

In this problem you will extend RectangleThing and OvalThing to produce SquareThing and CircleThing.  Partial definitions of SquareThing and CircleThing can be found in SquareThing.java and CircleThing.java.


Problem 4: Testing

The GUI program provided is not a complete test of your code.  In this problem you will carry out black-box testing on the classes that you have implemented.  You are advised to read Program Development in Java: Abstraction, Specification, and Object-Oriented Design Section 10.4 and 10.6 before you attempt this problem.  Also, when you submit your test cases and results, remember to provide clear documentation as to which constructor(s) and/or method(s) you are testing in each case and provide justification for each of your test cases.

Appendix A: FigureThing Specification

  abstract class FigureThing implements Cloneable
  {
    // Overviews:
    // FigureThing is an abstraction of a figure object.
    // This class is abstract and must be overridden by a subclass.
    // FigureThings are mutable and cloneable.
    //
    // A typical FigureThing consists of a set of properties:
    // {location, color, shape, size}
    //

    public FigureThing()
     // effects: Initializes this with a random color
     //          such that its location is (0, 0).

    public abstract void draw(Graphics g);
     // effects: draws this onto g

    public abstract boolean hitTest(Point pt);
     // effects: returns true if the point pt lies inside the bounding rectangle
     //          of this. Returns false otherwise.

    public abstract Rectangle getBounds();
     // effects: returns the bounding rectangle of this.

    public abstract void setSize(int width, int height) throws ImpossibleSizeException;
     // modifies: this
     // effects: Resizes this so that its bounding rectangle has width
     //          <width> and height <height>,
     //          unless this cannot be resized to the specified dimension
     //             => no modifications to this, throw ImpossibleSizeException.
     //                (the exception suggests an alternative dimension
     //                 that is supported by this)

    public Object clone() throws CloneNotSupportedException
     // effects: standard clone operator

    public Point getLocation()
     // effects: returns the top left corner of the
     //          bounding rectangle of this.

    public void setLocation(Point pt)
     // modifies: this
     // effects: moves this to pt, i.e. this.getLocation()
     //          returns pt after call has completed.

    public Color getColor()
     // effects: returns this's color

    public void setColor(Color c)
     // modifies: this
     // effects: sets this's color to be c
  }
 

Appendix B: AnimatedThing Specification

  abstract class AnimatedThing extends FigureThing implements Animatible
  {
    // Overviews: An AnimatedThing is a FigureThing with an additional property:
    //            velocity.  Thus, a typical AnimatedThing is
    //            {location, color, shape, size, velocity}
    //

    AnimatedThing()
     // effects: Initializes an AnimatedThing object in a similar way to
     //          initializing a FigureThing object.  Each of the horizontal
     //          and vertical velocities of the new object is set to a random
     //          integral value i s.t. -3 <= i <= 3 and i != 0

    public void setVelocity(int vx, int vy)
     // modifies: this
     // effects: Sets the horizontal velocity of this to vx and
     //          the vertical velocity of this to vy.

    public int getHVelocity()
     // effects: Returns the horizontal velocity of this.

    public int getVVelocity()
     // effects:  Returns the vertical velocity of this.

    public void step(Dimension bound)
     // modifies: this
     // effects: Let p = location
     //              v = (vx, vy) = velocity
     //              r = the bounding rectangle of this
     //          Set p_post = p + v
     //          unless doing so will bring part of r outside bound
     //             => If the horizontal component of the attempted motion
     //                of r is away from the center of bound,
     //                   set vx_post = -vx
     //                And if the vertical component of the attempted motion
     //                of r is away from the center of bound,
     //                   set vy_post = -vy
     //                Set p_post = p

    public Object clone() throws CloneNotSupportedException
     // effects: standard clone operator
  }
 

Appendix C: Animatible Interface

  interface Animatible
  {
    // Overviews: Animatibles are objects that can be animated.
    //            Animation is achieved by invoking a number of steps
    //            of small modifications, movements, or transformations
    //            on this.

    public void step(Dimension bound);
     // modifies: this
     // effects: Updates the state of this to the appropriate value for
     //          the next animation step.  The argument bound indicates
     //          the dimension of the area within which this is allowed
     //          to move.
  }