Aquarium Lab Series
Lab:
Fish With Class
Implementing Classes
This set of Lab Exercises is the fifth in a series in which students
build a small program with several fish moving around in an aquarium.
The set includes the following exercises:
Each section contains an Introduction to a problem
or task
and an Exercise.
In the exercises that precede this one, students will have created a
vector of fish that move randomly back and forth in an aquarium,
being careful not to hit the sides.
Students should understand how to
identify the responsibilities of different classes,
construct class methods,
and use instance variables within methods.
Ascending and Descending Fish
Introduction
Our program would be much more interesting if the fish moved up and down
as well as side to side.
In this exercise, you will implement two new methods in the
AquaFish class, ascend and descend,
to support this behavior.
Exercise: Simulation Up and Down Movement
- To make the simulation more believable, the distance that a fish moves
up or down should be related to its height. Fish come in different sizes,
so the size of any particular fish is one of the properties of that
fish. Its position in the aquarium is another relevant property for
this exercise. Read the implementation
(code) for the AquaFish class to determine which methods or instance
variables will be useful in implementing
ascend and descend.
- Determine what parameters (if any) you will need for the new
ascend
method. Then determine what its return type should be. Add an empty
ascend method (one that consists of a declaration and empty
braces) to the AquaFish class after the moveForward
and changeDir methods.
- Implement the
ascend method. You may use the moveForward
method as a guide if you like, but the ascend method is
simpler. The movement amount should simply be the height of the fish.
Research the specification for the AquaPoint
class to discover what methods might be useful in implementing the ascend
and descend methods.
- Implement the
descend method.
- Modify your
main method in the AquaSimApplication
class to allow fish to ascend or descend before moving forward, according
to the following formula:
- A fish at the surface has a 2/3 chance of descending and a 1/3
chance of staying at the surface.
- A fish at the bottom has a 1/3 chance of ascending and a 2/3 chance
of staying at the bottom.
- A fish that is neither at the surface nor at the bottom has a
1/3 chance of ascending, a 1/3 chance of descending, and a 1/3 chance
of staying at the same depth.
Read the implementation (code)
for the AquaFish class to determine what methods are available to
tell whether a fish is at the surface, at the bottom, or somewhere in
between. (These methods do not appear in the partial specification
for the AquaFish class that you have used previously.)
- Test your program.
|
Responsible Fish
Introduction
One of the most important tasks in designing and implementing
object-oriented programs is deciding which classes or objects are
responsible for executing which behavior. Up until now, all of the
behavior that you have added to the Aquarium Simulation program has been
in the main method of the AquaSimApplication
class. Now it's time to make the program more object-oriented.
For example,
deciding whether a fish should change direction or ascend or descend
when it moves should
be the responsibility of the fish, not of the simulation program.
In this exercise, you will implement a move method in the
AquaFish class that will encapsulate all of the
behavior related to movement (ascending, descending, changing
direction, and moving forward).
Exercise: Make Fish Responsible for Knowing How to Move
- Analyze the
main method of the AquaSimApplication
class to determine which lines of code should be moved to the move
method you will be implementing in the AquaFish class.
- Determine what parameters (if any) you will need for the new
move
method. Then determine what its return type should be. Add an empty
move method (one that consists of a declaration and empty
braces) to the AquaFish class before the moveForward
method.
- Move the appropriate lines of code from the
main method
in AquaSimApplication to the move in AquaFish.
Notice that the main method was invoking AquaFish
methods such as changeDir on a named fish. The move
method, though, is tied to the AquaFish class. More specifically,
it is always tied to (or executed by) a particular fish. Thus, instead
of main invoking methods such as changeDir
on a named fish, the fish should now be invoking methods on itself.
- Modify the
main method in AquaSimApplication
to simply tell each fish to move, letting the fish worry about how
it should move.
- Test your program to verify that the behavior is unchanged.
|
Modeling a Simulation
Introduction
In a well-designed object-oriented program, we usually want the
main function to just create some objects and get the ball
rolling.
Most of the program behavior should be the result of the objects
interacting with each other.
In the Aquarium Simulation program, though, the main
function is actually running the simulation.
We have objects that model the fish and the aquarium,
but not one that models the simulation itself.
In this exercise, you will write the code for methods in a
Simulation class. The constructor will initialize the
Simulation object's instance variables and construct the
fish in the aquarium.
The step method will
execute the commands that should happen each timestep in the simulation
(moving the fish, in our case).
Once you have implemented the Simulation class, the main
method in AquaSimApplication will merely create a number of objects,
such as the aquarium, the graphical user interface, and the simulation object,
and then ask the simulation object to run the simulation. The main
method will also still display the initial configuration of the fish and the
modified aquarium after each timestep.
Exercise: Introduce the Simulation Class
- Read the specification for the
Simulation class to familiarize yourself with what the class should
do.
- Download the incomplete Simulation
class implementation if you don't have it already.
- Read the incomplete
Simulation class implementation
and then modify the constructor to initialize the instance variables.
Notice that Simulation objects have three instance
variables and that the constructor takes three parameters. Two of
the three instance variables represent the same objects as two of
the parameters, so you can initialize them directly. For example,
the main method in AquaSimApplication
will construct an Aquarium and pass it to the Simulation
constructor. The Simulation object should refer to
the same Aquarium object, not a new one. On the other
hand, looking at the parameters to the Simulation constructor,
we can see that the main method will not construct
an array of fish and pass it to the constructor. Instead, it will
pass the number of fish that should be in the array. Therefore,
to initialize the allFish instance variable, you will
need to construct a new array of fish.
- Move the appropriate lines of code that construct various colored
fish (but not the lines that display them)
from the
main method in AquaSimApplication
to the Simulation constructor. Double-check whether the
instance variables in the Simulation constructor have
the same names that the local variables in the main method
had.
Stop and Think
Now that the fish are not constructred in the main
method, how can the code pass them to the user interface to
display? Research the class documentation for the
Simulation class to find a method that will be
useful in solving this problem.
- Replace the code in the
main method that constructed
all the fish with a statement that constructs a Simulation
object.
- Determine what code in
main represents a single timestep
in the simulation. Move that code to the step method
in Simulation. Adjust any variable names if necessary.
- Replace the code in the
main method that represented
a single timestep in the simulation with a call to the step
method in Simulation.
- Test your program to verify that the behavior is unchanged.
Analysis Questions
- Notice that the constructor uses instance variables, parameters, and
local variables. For example, the following statement
allFish.add(new AquaFish(aqua, color));
uses two instance variables and two local variables. How can you
determine whether a given identifier is a local variable, a parameter,
or an instance variable?
- If you had the following code
ArrayList<AquaFish> allFish = new ArrayList<AquaFish>();
// WARNING!
...
allFish.add(new AquaFish(aqua, color));
in the constructor, would you be putting new fish in the instance
variable called allFish or in a local variable? How would
this affect the behavior of the step method?
|
Adding Step and Run Buttons
Introduction
The user of the Aquarium Simulation program can control how many fish to
put in the aquarium and how many simulation steps to run, but cannot
control the pace of the simulation. We can give the user more control
over how the simulation runs by providing Step and Run buttons.
Exercise: Allow User to Control Simulation
- The
AquaSimGUIwithSimulation class is a subclass
of AquaSimGUI. It has step and run buttons added
to the user interface that control the running (and displaying)
of the simulation. It also prompts the user for the number of
fish and simulation steps for you, and constructs a
Simulation object.
Research the abbreviated
specification for the
AquaSimGUIwithSimulation
class to discover how to modify your code to construct an
object of type AquaSimGUIwithSimulation instead
of type AquaSimGUI.
- Modify the
main
method in AquaSimApplication to
construct the graphical user interface. Once you
have done this you no longer need to ask for the number of
fish or number of simulation steps, construct
the Simulation object, display the aquarium, or run the simulation. The
graphical user interface will do all of that. Therefore, the construction
of the graphical user interface should be the last line of code before
the WRAP UP phase.
- Test your program to verify that the behavior is unchanged.
- Make sure that you have updated the program documentation in all modified
classes to reflect your changes.
|
Copyright Alyce Faulstich Brady, 2001-2002.