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 9 6

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. 9.9), Employee (Fig. 9.10) and EmployeeTest (Fig. 9.11). Class Date (Fig. 9.9) declares instance variables month, day and year (lines 79) to represent a date. The constructor receives three int parameters. Line 15 implicitly invokes the set accessor of property Month (lines 4150) to validate the monthan out-of-range value is set to 1 to maintain a consistent state. Line 16 similarly uses property Year to set the yearbut notice that the set accessor of Year (lines 2831) assumes that the value for year is correct and does not validate it. Line 17 uses property Day (lines 5478), which validates and assigns 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). Note that the order of initialization is important because the set accessor of property Day validates the value for day based on the assumption that month and year are correct. Line 66 determines whether the day is correct based on the number of days in the particular Month. If the day is not correct, lines 6970 determine whether the Month is February, the day is 29 and the Year is a leap year. Otherwise, if the parameter value does not contain a correct value for day, line 75 sets day to 1 to maintain the Date in a consistent state. Note that line 18 in the constructor outputs the this reference as a string. Since this is a reference to the current Date object, the object's ToString method (lines 8184) is called implicitly to obtain the object's string representation.

Figure 9.9. Date class declaration.

1 // Fig. 9.9: Date.cs 2 // Date class declaration. 3 using System; 4 5 public class Date 6 { 7 private int month; // 1-12 8 private int day; // 1-31 based on month 9 private int year; // any year (could validate) 10 11 // constructor: use property Month to confirm proper value for month; 12 // use property Day to confirm proper value for day 13 public Date( int theMonth, int theDay, int theYear ) 14 { 15 Month = theMonth; // validate month 16 Year = theYear; // could validate year 17 Day = theDay; // validate day 18 Console.WriteLine( "Date object constructor for date {0}", this ); 19 } // end Date constructor 20 21 // property that gets and sets the year 22 public int Year 23 { 24 get 25 { 26 return year; 27 } // end get 28 private set // make writing inaccessible outside the class 29 { 30 year = value; // could validate 31 } // end set 32 } // end property Year 33 34 // property that gets and sets the month 35 public int Month 36 { 37 get 38 { 39 return month; 40 } // end get 41 private set // make writing inaccessible outside the class 42 { 43 if ( value > 0 && value <= 12 ) // validate month 44 month = value; 45 else // month is invalid 46 { 47 Console.WriteLine( "Invalid month ({0}) set to 1.", value ); 48 month = 1; // maintain object in consistent state 49 } // end else 50 } // end set 51 } // end property Month 52 53 // property that gets and sets the day 54 public int Day 55 { 56 get 57 { 58 return day; 59 } // end get 60 private set // make writing inaccessible outside the class 61 { 62 int[] daysPerMonth = 63 { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; 64 65 // check if day in range for month 66 if ( value > 0 && value <= daysPerMonth[ Month ] ) 67 day = value; 68 // check for leap year 69 else if ( Month == 2 && value == 29 && 70 ( Year % 400 == 0 || ( Year % 4 == 0 && Year % 100 != 0 ) ) ) 71 day = value; 72 else 73 { 74 Console.WriteLine( "Invalid day ({0}) set to 1.", value ); 75 day = 1; // maintain object in consistent state 76 } // end else 77 } // end set 78 } // end property Day 79 80 // return a string of the form month/day/year 81 public override string ToString() 82 { 83 return string.Format( "{0}/{1}/{2}", Month, Day, Year ); 84 } // end method ToString 85 } // end class Date

Figure 9.10. Employee class with references to other objects.

(This item is displayed on page 429 in the print version)

1 // Fig. 9.10: Employee.cs 2 // Employee class with references to other objects. 3 public class Employee 4 { 5 private string firstName; 6 private string lastName; 7 private Date birthDate; 8 private Date hireDate; 9 10 // constructor to initialize name, birth date and hire date 11 public Employee( string first, string last, 12 Date dateOfBirth, Date dateOfHire ) 13 { 14 firstName = first; 15 lastName = last; 16 birthDate = dateOfBirth; 17 hireDate = dateOfHire; 18 } // end Employee constructor 19 20 // convert Employee to string format 21 public override string ToString() 22 { 23 return string.Format( "{0}, {1} Hired: {2} Birthday: {3}", 24 lastName, firstName, hireDate, birthDate ); 25 } // end method ToString 26 } // end class Employee

Figure 9.11. Composition demonstration.

(This item is displayed on page 430 in the print version)

1 // Fig. 9.11: EmployeeTest.cs 2 // Composition demonstration. 3 using System; 4 5 public class EmployeeTest 6 { 7 public static void Main( string[] args ) 8 { 9 Date birth = new Date( 7, 24, 1949 ); 10 Date hire = new Date( 3, 12, 1988 ); 11 Employee employee = new Employee( "Bob", "Blue", birth, hire ); 12 13 Console.WriteLine( employee ); 14 } // end Main 15 } // end class EmployeeTest  

Date object constructor for date 7/24/1949 Date object constructor for date 3/12/1988 Blue, Bob Hired: 3/12/1988 Birthday: 7/24/1949

Class Employee (Fig. 9.10) has instance variables firstName, lastName, birthDate and hireDate. Members birthDate and hireDate (lines 78) are references to Date objects, demonstrating that a class can have as instance variables references to objects of other classes. The Employee constructor (lines 1118) takes four parametersfirst, last, dateOfBirth and dateOfHire. The objects referenced by 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. 9.11) creates two Date objects (lines 910) to represent an Employee's birthday and hire date, respectively. Line 11 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 13 implicitly invokes the Employee's ToString method to display the values of its instance variables and demonstrate that the object was initialized properly.

Категории