Elementary patterns to use in writing client code that requires constructing and using objects.
Declare-Construct-Initialize (maybe this should
be "Declare-Construct-Initialize-Use" or "Well-Defined Variable")
Read the Interface for Constructors (maybe this
should be part of a "Constructor Specification" pattern, along with
information on writing constructors)
Read the Interface for Methods (maybe this
should be part of a "Method Specification" pattern, along with
information on writing methods)
The following related patterns are defined elsewhere. Better references/links will appear in time.
You are in a situation in which you want to create a new variable. If you are using a typed language, the type of the variable must be explicitly specified. There must be space set aside in memory for the variable, the size of which is determined by the type. Before you use the value of the variable, it must be set to a meaningful value.
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 in C++ or Java, Read the Interface for Constructors to determine how to construct and initialize the variable. You may not need to explicitly initialize the variable if it will automatically be given an appropriate default value or if you always set it in your algorithm before trying to use it.
For example, in C and 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 char, int,
and double), the variable will not be initialized unless you
do it explicitly, as in the second example below.
Class objects in C++ are always initialized by a constructor
function, which is invoked automatically by the program when you construct an
object.
For any given class,
Read the Interface for Constructors to determine
how to construct and initialize objects of the class.
In the example below,
MyType might be a type created with typedef in
C or a class name in C++.
int i; // constructs an integer (uninitialized)
int j = 0; // constructs an integer, initializing to 0
MyType newObject; // constructs newObject using default constructor
MyType newObject = oldObject; // constructs newObject as copy of oldObject
MyType newObject(initValue); // constructs newObject using initValue (C++)
In Java, a variable definition of a primitive type declares the type of an object and sets aside the memory for it (constructs it) simultaneously. It is also possible to initialize a variable of a primitive type at the same time.
int i; // constructs an integer (and initializes to 0)
int j = 0; // constructs an integer, initializing to 0
A variable associated with a class object in Java is actually a reference to the actual object. Creating the reference variable and associating it with an object are two separate steps. The variable declaration declares the type of object the variable will refer to, and initializes it by default to be a null reference, as in the example below.
MyClass myObj; // constructs reference
The variable can be assigned to refer
to an existing object, or to an explicitly constructed object.
A newly constructed object is initialized by a constructor method,
and it is often possible to pass parameters to a
constructor to affect the initialization. In Java, empty parentheses
are used when invoking the default constructor.
Again, for any given class,
Read the Interface for Constructors to determine
how to construct and initialize objects of the class.
MyClass newObject = oldObject; // constructs new reference to existing object
MyClass myObj = new MyClass(); // constructs, initializes using default constructor; assigns to reference
MyClass myObj = new MyClass(initValue); // constructs, initializes using one-parameter constructor; assigns to reference
It is possible to construct a reference to a new object in a single
line of code, but constructing the reference and the object
are still two distinct steps.
MyClass myObj = new MyClass(initValue); // constructs and initializes both reference and new MyClass object
It is not always necessary to specify the initial value of a newly
constructed variable.
Depending on the language you are using (and, in C or C++, the scope of
the variable), the variable may automatically be given a default value.
For example, if you construct an int in
Java without initializing it, it will be initialized to 0
by default. Similarly, in C++ and Java, if you construct an object of a
class that has a default constructor, the object will have the default
value provided by that constructor.
If this is not the appropriate starting value in the
context of
your program, you must pass initializing information to the constructor
as parameters.
Even
if the default
value is the appropriate initial value, you may still choose to
initialize the variable explicitly as a form of documentation.
Another context in which initialization is not necessary is when the
variable will always be set to a value before it is used. Consider, for
example, the following code fragment to calculate the average of an
array of N floating point numbers (of type double)
in C, C++, or Java. This fragment assumes that list is an
array of at least N values, and
that N is greater than 0.
double sum = 0, average;
int i;
for (i = 0; i < N; i++)
sum += list[i]; // list is an array of double
average = sum / N;
In this example, average is not initialized as it is
constructed but it is always set before it is used. In C++ or Java,
which do not require variable declarations to be at the beginning of
a block, we could construct average after
the for loop and initialize it at the same time.
// C++ or Java version
double sum = 0;
for (int i = 0; i < N; i++)
sum += list[i]; // list is an array of double
double average = sum / N;
*The Intention Revealing Name pattern is described 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).
You are in a situation in which you want to construct a new object of a class. You need to know whether any initial values are needed as the object is constructed.
Therefore, read the constructor specification(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 specifications.
A constructor specification will tell you
Reading a constructor or method specification and then writing code that meets the specification is tricky, especially for novices. This is because the client code you write will not look exactly like the specification. Think of the specification 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 a Java class called Aquarium. How do we find the constructors in the class? A constructor specification looks like a method whose name is the same as the class. Here is a constructor specification from the Aquarium class.
public Aquarium(int width, int height)
Construct an Aquarium with user-specified size.
Parameters: width - width of the aquarium when
displayed (in pixels)
height - height of the aquarium when
displayed (in pixels)
This specification tells us that the constructor is public, so we may
use it in our client code, and that it requires two integer
parameters. When we construct an Aquarium object 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 = new Aquarium(600, 400);(See the Declare-Construct-Initialize-Use pattern for more information on declaring and constructing new objects.)
What if the Aquarium class also includes a second constructor that takes no parameters?
public Aquarium() Construct an Aquarium with default size.In this case, we could use either constructor. We could construct an Aquarium with the default size (whatever that may be), with the following Java code:
Aquarium myAquarium = new Aquarium();
When writing code in C++, find accessible constructors by looking for the constructors following the appropriate keyword. A C++ example similar to the Java examples above might look like the following.
public:
Aquarium(int width, int height);
// Construct an Aquarium with user-specified size.
Aquarium();
// Construct an Aquarium with default size.
Again, this specification tells us that the constructor is public and
requires two integer parameters. We could construct a 600 x 400
Aquarium (or a pointer to one) as follows:
Aquarium myAquarium(600, 400); Aquarium * myAquariumPtr = new Aquarium(600, 400);We could construct a default Aquarium object (or a pointer to one) in C++ as follows:
Aquarium myAquarium; Aquarium * myAquariumPtr = new Aquarium;(See the Declare-Construct-Initialize-Use pattern for more information on declaring and constructing new objects.)
You are in a situation in which you want an object to do something, or you want to do something to an object of a class.
Therefore, read the method specifications in the class interface to determine how to invoke methods on the object (also known as "sending a message" to the object).
A method specification will tell you
Note: This pattern uses the term "method" to refer to the functions associated with a class. This is a common term in many object-oriented programming languages. In C++, however, methods are known as "member functions."
Let's look at two methods from an example Java class called Aquarium.
public int width()
Determine the width of the aquarium.
Returns: the width of the aquarium
public boolean validLoc(int xCoord, int yCoord)
Determine whether the given coordinates specify a valid location.
Parameters: xCoord - x coordinate of location to be checked
yCoord - y coordinate of location to be checked
Returns: true if specified location is within aquarium
The specifications in C++ would be very similar. The keyword
const after each member function indicates that the
function does not modify the Aquarium object (it is an "accessor"
function).
public:
int width() const;
// Construct an Aquarium with user-specified size.
bool validLoc(int xCoord, int yCoord) const;
// Construct an Aquarium with default size.
What can we learn from these declarations?
In either language, both methods are public,
so we may use them in client code. Both
have return values (width returns an
integer value; validLoc returns a
boolean value), so we should capture the value returned in a
variable or embed the method call in a larger expression. The
width method does not take any parameters and returns an
int.
The validLoc method requires two parameters and returns a
boolean value. Thus, this method may be used in a logical expression.
How can we use this knowledge?
If y is a well-defined integer value
(see the Declare-Construct-Initialize-Use pattern),
then the following are valid examples of these two methods in either C++
or Java.
int aquariumWidth = myAquarium.width(); if ( myAquarium.validLoc(myAquarium.width() / 2, y) ) ...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 method as you call it.
A method with a void return type does not return any value
to the method 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 specification of a void method from a Java class
called Display.
public void setTitle(String s)
Set the title to appear in the Title Bar of the "window".
Parameters: s - the title
In C++, the specification of this modifying (non-const)
member function would be:
public:
void setTitle(string s);
// Set the title to appear in the Title Bar of the "window".
Since setTitle does not return anything, it cannot be
embedded in an expression or an assignment statement. A
void method is a statement on its own. For example, the
following line of code will modify the title bar of the display window
in either C++ or Java.
theDisplay.setTitle ("Aquarium Simulation");