CS111 LAB 9 - Inheritance and Polymorphism

Learning Objective (The same as HW 9)

Build upon our knowledge of user-defined classes, and gain experience using inheritance and polymorphism to create a class hierarchy. Inheritance will be used to consolidate code (behavior and data) shared among multiple classes at the most general level, and polymorphism will be used to treat specific objects as members of a general class.

Before you start...

This lab is to help you with homework 9. Before you start lab 9 please read instructions of homework 9 carefully.

Programming Assignment (The same as HW 9)

A screen saver is an application which runs on a computer when it has been idle for some time. Usually, the screen saver draws some graphics on the screen and animates these graphics in some way. In this homework, you will create three classes which can be drawn by a screen saver engine.

Since the objective is to learn about using inheritance and polymorphism, the actual ScreenSaver implementation will be provided to you. You will build a screen saver that displays an animated aquarium scene like the one shown below.

Your task will be to create the classes to represent the types of animals that will be drawn by the screen saver. The hierarchy of classes that you will implement is shown below.

Detailed Requirements (The same as HW 9)

AquariumAnimal and Fish will be abstract superclasses that contain fields and/or methods that are common to their subclasses. The other three classes (Snail, Goldfish, and Guppy) will be non-abstract classes that will be used to construct the objects that represent the individual animals on the screen.

We give you the basic requirements for these classes below, but it is up to you to implement them in a correct and concise way. In particular, your class implementations must take advantage of inheritance by putting instance variables and methods that are common to multiple classes in the appropriate superclass. Doing so will allow you to avoid duplicating code, since code that is shared by multiple classes can be written once and inherited in the subclasses. Also, your implementation of these classes must work with the driver class ScreenSaver, so make sure to read over the code in that class to understand how your class hierarchy will be utilized.

Here is what you need to know in order to decide which instance variables and methods are needed, and in which class or classes they should be defined:

  • All aquarium animals have an x-coordinate and a y-coordinate on the screen, and there should be accessor and mutator methods for these coordinates (getX(), getY(), setX(), and setY()). Since these accessor and mutator methods will do the same thing for all types of animals, they should only need to be defined once.

  • All aquarium animals need to have a draw() and move() method. However, these methods cannot be defined for an arbitrary animal, and thus they should be abstract methods in the AquariumAnimal class. Definitions of these methods for particular types of animals should go in the appropriate subclasses. Make sure that you don't duplicate code unnecessarily when defining these methods. If a given version of a method can be used by more than one type of animal, define it once in the superclass of those animals.

  • Each version of the move() method that you write should take no parameters and should update the coordinates of the animal on which it is invoked.

  • Each version of the draw() method that you write should take a single parameter of type Graphics and use this parameter to draw the animal on which it is invoked at its x and y coordinates using the appropriate color.

  • Neither move() nor draw() should return a value.

  • All fish (goldfish and guppies) have the same shape and can thus be drawn in the same way.

  • Snails are red, goldfish are gold, and guppies are blue. Depending on where the draw() method for a given type of animal is implemented, you may be able to specify the necessary Color object in the draw() method itself, or you may need to store the Color in an instance variable that the draw() method uses when setting the color used for drawing.

  • Each type of animal (snail, goldfish, and guppy) moves somewhat differently:
    • A snail moves from left to right along the bottom of the screen at a constant pace (increasing its x-coordinate by 2 on each move).
    • On a given move, a goldfish moves 10 units in one of four directions: up, down, left, or right. The direction should be chosen at random.
    • On a given move, a guppy moves 10 units in one of two directions: up or right. The direction should be chosen at random.

  • If an animal moves off the screen, it must reappear on the opposite side. For example, if a fish swims off the top of the screen, it must reappear at the same x-coordinate on the bottom of the screen.

  • All snails have the same y-coordinate, since they always crawl along the bottom of the tank. This y-coordinate should be represented as a named constant. Because the y-coordinate is always the same, the Snail constructor only needs a single parameter representing the x-coordinate.

  • The Goldfish and Guppy constructors should take two parameters: one for the x-coordinate, and one for the y-coordinate.

  • The AquariumAnimal constructor should take whatever parameters are needed to initialize the instance variables that it maintains.

  • The Fish constructor should take whatever parameters are needed to initialize the instance variables that either it or its superclass maintains.

  • The Snail, Fish, Goldfish, and Guppy constructors should each invoke their superclass constructor, passing it whatever information it needs.

Here are some other suggestions/hints:

  • You may want to consult your code for HW 3 to review the use of methods from the Graphics class for drawing.

  • Consider using the Graphics method fillPolygon() to color in an arbitrary region, for example for the fish tails.

  • Use named constants when appropriate (e.g., for the distance that a snail advances on a given move, and for the distance that a fish advances on a given move).

  • You can choose a direction at random by using the Math.random() method. For example, int direction = (int)(2 * Math.random()) will assign to the variable direction one of two values (0 or 1), and you can use each of these values to represent a different direction.

The ScreenSaver class

We are providing you with the client class ScreenSaver, which creates an array of AquariumAnimal and repeatedly moves and draws them. This class takes advantage of the power of polymorphism, which allows objects of any subclass of AquariumAnimal to be stored in the same array. When a method is invoked on an animal stored in the array (e.g., animals[i].move()), the appropriate version of the method for that type of animal will be invoked! Aside from adding a package declaration to this file, you should not need to change it.

In this lab...

You will implement 2 classes: AquariumAnimal and Snail in this lab. To test these two classes only, you could use a simple edition of Screen Saver SimpleScreenSaver. Here are templates for AquariumAnimal and Snail. You need to complete those two source code and test them with SimpleScreenSaver

Web submit

Academic Honesty and Collaboration

Cooperation is recommended in understanding programming concepts and system features. But the actual solution of the assignments including all programming must be your individual work. For example, copying without attribution any part of someone else's program is plagiarism, even if you have modified the code. The University takes acts of cheating and plagiarism very seriously; first time violators are routinely suspended for a semester.

CS111 Home