Course Links

Resources

External

This lab will give you some practice working with subtypes in Java. Because it uses a number of different files, the instructions are all gathered on this web page rather than scattered in comments within the files.

To get started, download and unzip the zip file containing all the files for this lab. This time all the files are in one folder, but they are numbered according to the part of the lab.

Part 1

For this part we will be working with just four of the provided files:

You can compile these all together with the following command:

javac RunPointCanvas.java PointCanvas.java StarPoints.java CirclePoints.java
Notice that with the Java compiler we don't specify a -o option. The output files will all have the same name as their source files. You will run the program with this command (don't include .java here!):

java RunPointCanvas

Begin by looking at StarPoints.java. You will see that it is a fairly simple class with three fields. The most interesting method is getPointArray, which is required by the PointGenerator interface. Here is the definition of that interface:

interface PointGenerator {
    public Point[] getPointArray();
}

Class PointCanvas relies on objects of this type to carry out its drawing. For each such object, it calls the getPointArray method to get an array of points. Then it draws a line connecting each consecutive point in the array. How does it know which objects to call? Look now at RunPointCanvas.java. You will see that it creates a PointCanvas object called pc and its registerPoints method for each of the objects we plan to display. Here is the call signature for registerPoints:

public void registerPoints(PointGenerator pg);

Notice that it takes an object of type PointGenerator as input -- that means any object that implements the interface. Note that PointCanvas doesn't need to know anything about the internal details of such an object. As long as it properly implements the method specified in the interface, everything should "just work". In particular, it can be an object of a newly created class that didn't even exist when PointCanvas was written. As long as it obeys the contract, it will work.

Exercise 1: Your goal is to write a new class of shape for display on the PointCanvas. Take a look at CirclePoints.java, which gives you a second example of a class implementing the PointGenerator interface. Note how it differs from StarPoints.java, and how it is similar. Now create a new file named SquarePoints.java that will give us points in a square. (How many points will you need to return in your array?) When you finish it, add code to RunPointCanvas to make some squares appear in your graphics.

Part 2

For this part you will continue to use PointCanvas.java, but you will shift to using RunPointCanvas2.java, StarPoints2.java, and CirclePoints2.java.

The new files introduce an additional feature of PointCanvas: under the right conditions, the patterns drawn on the canvas can be dragged around by the mouse! Compile and run the new program and test it out. Neat, huh? The movement happens via a second interface, shown below:

interface Displaceable extends PointGenerator {
  public int getX();
  public int getY();
  public void move(int dx, int dy);
}

As with PointGenerator, there is a method to tell the PointCanvas about objects that can be dragged. It is called registerDisplaceable. Look inside RunPointCanvas2.java to see how it is used. Next look at StarPoints2.java to see the changes that were made in order to support this new functionality:

  1. Both interfaces are listed as implemented by the class on line 7. (Technically we only need to list Displaceable; since it extends PointGenerator is automatically included with it.
  2. We create a new field to remember the array of points. This is necessary because we will have to loop through them and update each one whenever the move method gets called.
  3. Since the array of points is now a field of the object, we initilize it in the constructor instead of getPointArray.
  4. Now getPointArray becomes simpler, since it merely returns the array that has already been set up.
  5. We add three new methods to satisfy the contract for Displaceable. Two are simple accessors for x and y. The last one updates the positions of all the points, looping though the array and moving them all by the specified amount.

Exercise 2: To complete this section, you will copy SquarePoints.java into SquarePoints2.java and update it so that your PointCanvas can have moveable squares on it. Add some squares in RunPointCanvas2.java and run it to make sure everything works.

Part 3

For this part you will continue to use PointCanvas.java, but you will shift to using RunPointCanvas3.java, StarPoints3.java, and CirclePoints3.java, plus the new file PointObject.java.

This part doesn't add any new functionality. However, it does simplify the code, and in doing so it makes use of a second form of subtyping: inheritance. You may have noticed that the various point shape classes all have a lot in common. Usually, when you have a lot of code that is repeated in many places, there is some refactoring possible that will condense the code and eliminate that duplication. That is indeed the case here.

Since we have several classes that all do much the same thing, we can create a single parent class that implements all the shared behavior, and use inheritance to share that implementation. Look at PointObject.java. You will see that it looks similar to the StarPoints2.java and CirclePoints2.java from the last part. Now look at StarPoints3.java and CirclePoints3.java -- they are very different, and much simpler. We don't have to write nearly as much, because they inherit almost everything. The only thing unique to each class is the constructor, which sets up the particular pattern of points for this shape. Because we've put all the common code into PointObject and inherit from it, all that is left to write is the part that makes each shape unique. Win!

Exercise 3: Create SquarePoints3.java using the same strategy, and add some examples to the PointCanvas. If you do this and the program works, you are done!

If you like, you may check your answers against the sample solutions: part 1, part 2, part 3.