Composition
A class can have references to objects of other classes as members. Such a capability 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 is supposed to sound its alarm, so it is reasonable to include two references to Time objects as members of the AlarmClock object.
Software Engineering Observation 8.9
One form of software reuse is composition, in which a class has as members references to objects of other classes. |
Our example of composition contains three classesDate (Fig. 8.7), Employee (Fig. 8.8) and EmployeeTest (Fig. 8.9). Class Date (Fig. 8.7) declares instance variables month, day and year (lines 68) to represent a date. The constructor receives three int parameters. Line 14 invokes utility method checkMonth (lines 2333) to validate the monthan out-of-range value is set to 1 to maintain a consistent state. Line 15 assumes that the value for year is correct and does not validate it. Line 16 invokes utility method checkDay (lines 3652) to validate the value for day based on the current month and year. Lines 4243 determine whether the day is correct based on the number of days in the particular month. If the day is not correct, lines 4647 determine whether the month is February, the day is 29 and the year is a leap year. If lines 4248 do not return a correct value for day, line 51 returns 1 to maintain the Date in a consistent state. Note that lines 1819 in the constructor output the this reference as a String. Since this is a reference to the current Date object, the object's toString method (lines 5558) is called implicitly to obtain the object's String representation.
Figure 8.7. Date class declaration.
(This item is displayed on pages 374 - 375 in the print version)
1 // Fig. 8.7: Date.java 2 // Date class declaration. 3 4 public class Date 5 { 6 private int month; // 1-12 7 private int day; // 1-31 based on month 8 private int year; // any year 9 10 // constructor: call checkMonth to confirm proper value for month; 11 // call checkDay to confirm proper value for day 12 public Date( int theMonth, int theDay, int theYear ) 13 { 14 month = checkMonth( theMonth ); // validate month 15 year = theYear; // could validate year 16 day = checkDay( theDay ); // validate day 17 18 System.out.printf( 19 "Date object constructor for date %s ", this ); 20 } // end Date constructor 21 22 // utility method to confirm proper month value 23 private int checkMonth( int testMonth ) 24 { 25 if ( testMonth > 0 && testMonth <= 12 ) // validate month 26 return testMonth; 27 else // month is invalid 28 { 29 System.out.printf( 30 "Invalid month (%d) set to 1.", testMonth ); 31 return 1; // maintain object in consistent state 32 } // end else 33 } // end method checkMonth 34 35 // utility method to confirm proper day value based on month and year 36 private int checkDay( int testDay ) 37 { 38 int daysPerMonth[] = 39 { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; 40 41 // check if day in range for month 42 if ( testDay > 0 && testDay <= daysPerMonth[ month ] ) 43 return testDay; 44 45 // check for leap year 46 if ( month == 2 && testDay == 29 && ( year % 400 == 0 || 47 ( year % 4 == 0 && year % 100 != 0 ) ) ) 48 return testDay; 49 50 System.out.printf( "Invalid day (%d) set to 1.", testDay ); 51 return 1; // maintain object in consistent state 52 } // end method checkDay 53 54 // return a String of the form month/day/year 55 public String toString() 56 { 57 return String.format( "%d/%d/%d", month, day, year ); 58 } // end method toString 59 } // end class Date |
Figure 8.8. Employee class with references to other objects.
(This item is displayed on pages 375 - 376 in the print version)
1 // Fig. 8.8: Employee.java 2 // Employee class with references to other objects. 3 4 public class Employee 5 { 6 private String firstName; 7 private String lastName; 8 private Date birthDate; 9 private Date hireDate; 10 11 // constructor to initialize name, birth date and hire date 12 public Employee( String first, String last, Date dateOfBirth, 13 Date dateOfHire ) 14 { 15 firstName = first; 16 lastName = last; 17 birthDate = dateOfBirth; 18 hireDate = dateOfHire; 19 } // end Employee constructor 20 21 // convert Employee to String format 22 public String toString() 23 { 24 return String.format( "%s, %s Hired: %s Birthday: %s", 25 lastName, firstName, hireDate, birthDate ); 26 } // end method toString 27 } // end class Employee |
Figure 8.9. Composition demonstration.
(This item is displayed on page 376 in the print version)
1 // Fig. 8.9: EmployeeTest.java 2 // Composition demonstration. 3 4 public class EmployeeTest 5 { 6 public static void main( String args[] ) 7 { 8 Date birth = new Date( 7, 24, 1949 ); 9 Date hire = new Date( 3, 12, 1988 ); 10 Employee employee = new Employee( "Bob", "Blue", birth, hire ); 11 12 System.out.println( employee ); 13 } // end main 14 } // end class EmployeeTest
|
Class Employee (Fig. 8.8) has instance variables firstName, lastName, birthDate and hireDate. Members birthDate and hireDate (lines 89) are references to Date objects. This demonstrates that a class can have as instance variables references to objects of other classes. The Employee constructor (lines 1219) takes four parametersfirst, last, dateOfBirth and dateOfHire. The objects referenced by the parameters dateOfBirth and dateOfHire are assigned to the Employee object's birthDate and hireDate instance variables, respectively. Note that when class Employee's toString method is called, it returns a String containing the String representations of the two Date objects. Each of these Strings is obtained with an implicit call to the Date class's toString method.
Class EmployeeTest (Fig. 8.9) creates two Date objects (lines 89) to represent an Employee's birthday and hire date, respectively. Line 10 creates an Employee and initializes its instance variables by passing to the constructor two Strings (representing the Employee's first and last names) and two Date objects (representing the birthday and hire date). Line 12 implicitly invokes the Employee's toString method to display the values of its instance variables and demonstrate that the object was initialized properly.