10.7 Composition

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.

Software Engineering Observation 10.8

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.

10.7.1 Class 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.

Fig. 10.7 Date class declaration.

Alternate View

 1    // Fig. 10.7: 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       public int Year { get; private set;} // auto-implemented property Year
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 month, int day, int year)
14       {
15          Month = month; // validates month
16          Year = year; // could validate year
17          Day = day; // validates day
18          Console.WriteLine($"Date object constructor for date {this}");
19       }
20   
21       // property that gets and sets the month
22       public int Month
23       {
24           get
25           {
26              return month;
27           }
28          private set // make writing inaccessible outside the class
29          {
30             if (value <= 0 || value > 12) // validate month
31             {
32             throw new ArgumentOutOfRangeException(
33                nameof(value), value, $"{nameof(Month)} must be 1-12");
34             }
35
36             month = value;
37          }
38       }
39
40       // property that gets and sets the day
41       public int Day
42      {
43          get
44          {
45             return day;
46          }
47          private set // make writing inaccessible outside the class
48          {
49              int[] daysPerMonth =
50              {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
51
52         // check if day in range for month
53         if (value <= 0 || value > daysPerMonth[Month])
54         {
55           throw new ArgumentOutOfRangeException(nameof(value), value,
56            $"{nameof(Day)} out of range for current month/year");
57        }
58        // check for leap year
59        if (Month == 2 && value == 29 &&
60            !(Year % 400 == 0 || (Year % 4 == 0 && Year % 100 != 0)))
61        {
62            throw new ArgumentOutOfRangeException(nameof(value), value,
63                 $"{nameof(Day)} out of range for current month/year");
64        }
65   
66        day = value;
67       }
68      }
69
70       // return a string of the form month/day/year
71       public override string ToString() => $"{Month}/{Day}/{Year}";
72    }

Constructor

The constructor (lines 13–19) receives three ints. 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 Accessors

Class 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.

10.7.2 Class 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 strings is obtained with an implicit call to the Date class’s ToString method.

Fig. 10.8 Employee class with references to other objects.

Alternate View

 1    // Fig. 10.8: Employee.cs
 2    // Employee class with references to other objects.
 3    public class Employee
 4    {
 5        public string FirstName { get; }
 6        public string LastName { get; }
 7        public Date BirthDate { get; }
 8        public Date HireDate { get; } 
 9   
10       // constructor to initialize name, birth date and hire date
11       public Employee(string firstName, string lastName,
12          Date birthDate, Date hireDate)
13       {
14          FirstName = firstName;
15          LastName = lastName;
16          BirthDate = birthDate;
17          HireDate = hireDate;
18       }
19
20       // convert Employee to string format
21       public override string ToString() => $"{LastName}, {FirstName} " +
22           $"Hired: {HireDate} Birthday: {BirthDate}";
23    }

10.7.3 Class 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 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 Employee’s string representation and demonstrate that the object was initialized properly.

Fig. 10.9 Composition demonstration.

Alternate View

 1    // Fig. 10.9: EmployeeTest.cs
 2    // Composition demonstration.
 3    using System;
 4
 5    class EmployeeTest
 6    {
 7       static void Main()
 8       {
 9          var birthday = new Date(7, 24, 1949);
 10         var hireDate = new Date(3, 12, 1988);
11          var employee = new Employee("Bob", "Blue", birthday, hireDate);
12
13           Console.WriteLine(employee);
14       }
15    }

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
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset