Reading Interfaces and Writing Client Code
This set of Mini-Lab Exercises is the first 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, (usually) abridged versions of one or more Patterns that will be useful in solving the problem or completing the task, and an Exercise.
Before working through this Mini-Lab,
students should understand the role of the
function in an application and the role of classes and objects.
Students should also have read over the patterns that appear in this
document before the lab.
mainfunction that runs the simulation. There is also an
Aquariumclass and an
AquaFishclass. The skeleton program constructs an
Aquariumobject in the
mainfunction; in the exercises that follow, you will be creating several
AquaFishobjects in the aquarium and directing them to move.
The program also contains a
Display class. There are actually two different
implementations of the
Display class. One produces a
text-based display of the fish in the aquarium; the other draws them
graphically using the CMU Graphics package*.
main function constructs a
Display object that you will use to display the
aquarium after you have created and moved the fish. Finally, the
program includes some utility classes and functions, including the
RandGen class from the Advanced Placement Marine Biology
Case Study+ for generating random numbers, and the
WaitNClear function, which is useful if you are using the
graphical implementation of the
mainfunction creates an aquarium, but it doesn't have any fish in it. We can use the Declare-Construct-Initialize pattern to create fish to go in the aquarium. The
AquaFishinterface gives the specifics on how to construct objects of the class.
Therefore, you should specify the type of the new variable (declare), set aside space for it in memory (construct), and (usually) initialize it to a meaningful value before you use it in your program. Give the variable an Intention Revealing Name to make your code easier to read, understand, and maintain. If the variable is an object of a class, Read the Interface for Constructors to determine how to construct and initialize the variable.
In C++, a
variable definition declares the type of an object and sets
aside the memory for it (constructs it) simultaneously. For
fundamental types (such as
double), the variable will not be initialized unless you
do it explicitly, as in the second example below.
Class objects are always initialized by a constructor function,
which is invoked automatically by the program when you construct an
A constructor may take parameters to initialize the object, in which
case you should list the parameters in parentheses when you construct
the object. A default constructor takes no parameters, in
which case you do not need (and should not have) any parentheses when you
construct the object.
For any given class, Read the Interface for Constructors to determine how to construct and initialize objects of the class.
int i; // constructs an integer (uninitialized) int j = 0; // constructs an integer, initializing to 0 MyClass newObject; // constructs a MyClass object using default constructor MyClass newObject(initValue); // constructs a MyClass object using constructor with one parameter
Therefore, all of the names in your programs (variables and parameters, classes, member functions) should denote the purpose of the item they refer to. Variables, for example, should be named for the objects they represent.
The Intention Revealing Name pattern is described more fully in Bergin's Coding at the Lowest Level: Coding Patterns for Java Beginners. The pattern comes from Kent Beck's Smalltalk Best Practice Patterns (Prentice Hall, 1997).
Therefore, read the constructor declaration(s) in the class interface to determine how to construct and initialize, if necessary, the object that you need. Concentrate on the constructors that are accessible to you; for example, if you are writing client code, read the public constructor declarations.
A constructor declaration will tell you
Reading a constructor or member function declaration and then writing code that satisfies the declaration is tricky, especially for novices. This is because the client code you write will not look exactly like the declaration. Think of the declaration as being like a dictionary entry. Imagine that you want to use the word "cat" in a sentence, but you're not sure of its meaning. You look it up in a dictionary and find the following.
Let's look at an example from the Aquarium class. In this class, there are two constructors. How do we know? A constructor declaration looks like a member function whose name is the same as the class. There are two "member functions" called Aquarium in the Aquarium class interface.
Since both are in the
Aquarium() // postcondition: width and height are initialized to 0 // (there are no valid locations in such an aquarium) Aquarium(int width, int height); // postcondition: Width() == width, Height() == height
publicpart of the class interface, we can use either one to construct an aquarium in client code. The first declaration tells us that there is a default constructor for an Aquarium, but that it has no valid locations. We could construct a default Aquarium as follows:
The second declaration tells us that there is also a constructor that allows us to initialize the Aquarium object to a specified height and width. When we construct an Aquarium object using this constructor we do not need to specify that it is public nor what the types of its parameters are, anymore than we have to specify that a cat is a noun when we use it in a sentence. We do, however, need to provide values for the two parameters. Thus, we could construct a 600 x 400 Aquarium as follows:
Aquarium myAquarium(600, 400);
Therefore, read the member function declarations in the class interface to determine how to invoke member functions for an object of the class (also known as "sending a message" to the object).
A member function declaration will tell you
Let's look at two
examples from the Aquarium class:
What can we learn from these declarations? Both member functions are public, so we may use them in client code. Both have return values (
int Width() const; // returns width of aquarium bool ValidLoc(int x_coord, int y_coord) const; // returns true if and only x_coord and y_coord represent a // valid location inside the aquarium
Widthreturns an integer value;
ValidLocreturns a boolean value), so we should capture the value returned in a variable or embed the member function call in a larger expression. The
Widthmember function does not take any parameters and returns an
ValidLocmember function requires two parameters and returns a boolean value. Thus, this member function may be used in a logical (
false) expression. Both functions are const member functions (indicated by the
constkeyword at the end of the function declaration), so neither function modifies its Aquarium object.
How can we use this knowledge?
y is a well-defined integer value
(see the Declare-Construct-Initialize pattern),
then the following are valid examples of these two member functions.
As with constructors, you do not need to specify the type of the parameters as you pass them (see the Read the Interface for Constructors pattern). Nor do you specify the return type of the member function as you call it.
int aquariumWidth = myAquarium.Width(); if ( myAquarium.ValidLoc(myAquarium.Width() / 2, y) ) ...
A member function with a
void return type does not return any value
to the function that called it. Instead, it usually modifies its object,
produces output, or changes the state of the program in some other
way. It may or may not require parameters.
Here is a declaration of a
void member function from the
void ShowAquarium(); // postcondition: aquarium passed to constructor has been displayed
ShowAquariumdoes not return anything, it cannot be embedded in an expression or an assignment statement. A
voidfunction call is a statement on its own. For example,
*The CMU Graphics Library was created by the Carnegie Mellon University School of Computer Science and is used in their introductory programming courses. It is available from Mark Stehlik's Advanced Placement page.
+The Aquarium series of labs is loosely based on the Advanced Placement Computer Science Marine Biology Simulation Case Study, available from the College Board for face-to-face teaching purposes.