Software Engineering with Properties and set and get Accessors

Using properties as described earlier in this chapter would seem to violate the notion of private data. Although providing a property with get and set accessors may appear to be the same as making its corresponding instance variable public, this is not the case. A public instance variable can be read or written by any property or method in the program. If an instance variable is private, the client code can access the instance variable only indirectly through the class's non-private properties or methods. This allows the class to control the manner in which the data is set or returned. For example, get and set accessors can translate between the format of the data used by the client and the format stored in the private instance variable.

Consider a Clock class that represents the time of day as a private int instance variable time, containing the number of seconds since midnight. Suppose the class provides a Time property of type string to manipulate this instance variable. Although get accessors typically return data exactly as it is stored in an object, they need not expose the data in this "raw" format. When a client refers to a Clock object's Time property, the property's get accessor could use instance variable time to determine the number of hours, minutes and seconds since midnight, then return the time as a string of the form "HH:MM:SS". Similarly, suppose a Clock object's Time property is assigned a string of the form "HH:MM:SS". Using the string capabilities presented in Chapter 16 and the method Convert.ToInt32 presented in Section 3.6, the Time property's set accessor could convert this string to an int number of seconds since midnight and store the result in the Clock object's private instance variable time. The Time property's set accessor can also provide data validation capabilities that scrutinize attempts to modify the instance variable's value to ensure that the value it receives represents a valid time (e.g., "12:30:45" is valid but "42:85:70" is not). We demonstrate data validation in Section 4.10. So, although a property's accessors enable clients to manipulate private data, they carefully control those manipulations, and the object's private data remains safely encapsulated (i.e., hidden) in the object. This is not possible with public instance variables, which can easily be set by clients to invalid values.

Properties of a class should also be used by the class's own methods to manipulate the class's private instance variables, even though the methods can directly access the private instance variables. Accessing an instance variable via a property's accessorsas in the body of method DisplayMessage (Fig. 4.7, lines 2829)creates a more robust class that is easier to maintain and less likely to malfunction. If we decide to change the representation of instance variable courseName in some way, the declaration of method DisplayMessage does not require modificationonly the bodies of property CourseName's get and set accessors that directly manipulate the instance variable will need to change. For example, suppose we want to represent the course name as two separate instance variablescourseNumber (e.g., "CS101") and courseTitle (e.g., "Introduction to C# Programming"). The DisplayMessage method can still use property CourseName's get accessor to obtain the full course name to display as part of the welcome message. In this case, the get accessor would need to build and return a string containing the courseNumber, followed by the courseTitle. Method DisplayMessage would continue to display the complete course title "CS101 Introduction to C# Programming," because it is unaffected by the change to the class's instance variables.

Software Engineering Observation 4 3

Accessing private data through set and get accessors not only protects the instance variables from receiving invalid values, but also hides the internal representation of the instance variables from that class's clients. Thus, if representation of the data changes (often to reduce the amount of required storage or to improve performance), only the properties' implementations need to changethe clients' implementations need not change as long as the services provided by the properties are preserved.