A class can have objects of values types or references to objects of other classes as members. This is called composition and is sometimes referred to as a has-a relationship. For example, an object of class AlarmClock
needs to know the current time and the time when it’s supposed to sound its alarm, so it’s reasonable to include two references to Time
objects in an AlarmClock
object.
One form of software reuse is composition, in which a class contains references to other objects. Recall that classes are reference types. A class can have a property of its own type—for example, a Person
class could have Mother
and Father
properties of type Person
that reference other Person
objects.
Date
Our example of composition contains three classes—Date
(Fig. 10.7), Employee
(Fig. 10.8) and EmployeeTest
(Fig. 10.9). Class Date
(Fig. 10.7) declares int
instance variables month
and day
(lines 7–8) and auto-implemented property Year
(line 9) to represent a date.
The constructor (lines 13–19) receives three int
s. Line 15 invokes property Month
’s set
accessor (lines 28–37) to validate the month—if the value is out-of-range the accessor throws an exception. Line 16 uses property Year
to set the year. Since Year
is an auto-implemented property, it provides no validation—we’re assuming in this example that Year
’s value is correct. Line 17 uses property Day
’s set
accessor (lines 47–67) to validate and assign the value for day
based on the current Month
and Year
(by using properties Month
and Year
in turn to obtain the values of month
and Year
).
The order of initialization is important, because property Day
’s set
accessor performs its validation assuming that Month
and Year
are correct. Line 53 determines whether the day is out of range, based on the number of days in the Month
and, if so, throw an exception. Lines 59–60 determine whether the Month
is February, the day is 29
and the Year
is not a leap year (in which case, 29
is out of range) and, if so, throw an exception. If no exceptions are thrown, the value for day
is correct and assigned to the instance variable at line 66. Line 18 in the constructor formats the this
reference as a string
. Since this
is a reference to the current Date
object, the object’s ToString
method (line 71) is called implicitly to obtain the Date
’s string
representation.
private set
AccessorsClass Date
uses access modifiers to ensure that clients of the class must use the appropriate methods and properties to access private
data. In particular, the properties Year
, Month
and Day
declare private
set
accessors (lines 9, 28 and 47, respectively)—these set
accessors can be used only within the class. We declare these private
for the same reasons that we declare instance variables private
—to simplify code maintenance and control access to the class’s data. Although the constructor, method and properties in class Date
still have all the advantages of using the set
accessors to perform validation, clients of the class must use the class’s constructor to initialize the data in a Date
object. The get
accessors of Year
, Month
and Day
are implicitly public
—when there’s no access modifier before a get
or set
accessor, the property’s access modifier is used.
Employee
Class Employee
(Fig. 10.8) has public
auto-implemented, getter-only properties First-Name
, LastName
, BirthDate
and HireDate
. BirthDate
and HireDate
(lines 7–8) refer to Date
objects, demonstrating that a class can have references to objects of other classes as members. This, of course, also is true of FirstName
and LastName
, which refer to String
objects. The Employee
constructor (lines 11–18) uses its four parameters to initialize the class’s properties. When class Employee
’s ToString
method is called, it returns a string
containing the string
representations of the two Date
objects. Each of these string
s is obtained with an implicit call to the Date
class’s ToString
method.
EmployeeTest
Class EmployeeTest
(Fig. 10.9) creates two Date objects (lines 9–10) to represent an Employee
’s birthday and hire date, respectively. Line 11 creates an Employee
and initializesits instance variables by passing to the constructor two string
s (representing the Employee
’s first and last names) and two Date
objects (representing the birthday and hire date). Line 13 implicitly invokes the Employee’s ToString
method to display the Employee
’s string
representation and demonstrate that the object was initialized properly.