Section 9.2. Time Class Case Study


9.2. Time Class Case Study

We begin with a substantial application that uses most of the object-oriented programming concepts presented in Chapters 4 through 8. We introduce the Object class, the ultimate "ancestor" of all classes in Visual Basic. Also, we explain method ToString, which can be used to obtain a String representation of any Visual Basic object.

Time Class Declaration

The application consists of classes Time (Fig. 9.1) and FrmTimeTest (Fig. 9.2). Class Time contains the information needed to represent a specific time in two popular formats. Class FrmTimeTest represents a GUI for class Time.

Figure 9.1. Time class declaration maintains the time in 24-hour format.

  1  ' Fig. 9.1: Time.vb  2  ' Represents time to clients in 12-hour and 24-hour clock formats.  3  Class Time  4     Inherits Object ' if omitted, Object is inherited implicitly  5  6     ' declare Integer instance variables for the hour, minute and second  7     Private hourValue As Integer ' 0 - 23  8     Private minuteValue As Integer ' 0 - 59  9     Private secondValue As Integer ' 0 - 59 10 11     ' Time constructor initializes instance variables 12     ' when a Time object is created 13     Public Sub New() 14        SetTime(12, 0, 0) ' initialize hour to noon; minute, second to 0 15     End Sub ' New 16 17     ' set a new time value using universal time, check validity of the 18     ' data, set invalid hour to noon, set invalid minute, second to zero 19     Public Sub SetTime(ByVal hh As Integer, _ 20        ByVal mm As Integer, ByVal ss As Integer) 21        Hour = hh ' set hourValue using Hour property 22        Minute = mm ' set minuteValue using Minute property 23        Second = ss ' set secondValue using Second property 24     End Sub ' SetTime 25 26     ' property Hour 27     Public Property Hour() As Integer 28        Get ' return hourValue 29           Return hourValue 30        End Get 31 32        Set(ByVal value As Integer) ' set hourValue 33           If (value >= 0 AndAlso value < 24) Then ' in range 0-23 34              hourValue = value ' value is valid 35           Else ' value is invalid 36              hourValue = 12 ' set to default of noon 37           End If 38        End Set 39     End Property ' Hour 40 41     ' property Minute 42     Public Property Minute() As Integer 43        Get ' return minuteValue 44            Return minuteValue 45        End Get 46 47        Set(ByVal value As Integer) ' set minuteValue 48           If (value >= 0 AndAlso value < 60) Then ' in range 0-59 49               minuteValue = value ' value is valid 50           Else ' value is invalid 51               minuteValue = 0 ' set to default of 0 52           End If 53        End Set 54     End Property ' Minute 55 56     ' property Second 57     Public Property Second() As Integer 58        Get ' return secondValue 59           Return secondValue 60        End Get 61 62        Set(ByVal value As Integer) ' set secondValue 63           If (value >= 0 AndAlso value < 60) Then ' in range 0-59 64              secondValue = value ' value is valid 65           Else ' value is invalid 66              secondValue = 0 ' set to default of 0 67           End If 68        End Set 69     End Property ' Second 70 71     ' convert Time to a String in universal-time (24-hour clock) format 72     Public Function ToUniversalString() As String 73        Return String.Format("{0}:{1:D2}:{2:D2}", Hour, Minute, Second) 74     End Function ' ToUniversalString 75 76     ' convert Time to a String in standard-time (12-hour clock) format 77     Public Overrides Function ToString() As String 78        Dim suffix As String ' AM or PM suffix 79        Dim standardHour As Integer ' a standard hour in the range 1-12 80 81        ' determine whether the 12-hour clock suffix should be AM or PM 82        If Hour < 12 Then 83           suffix = "AM" ' note space preceding AM 84        Else 85           suffix = "PM" ' note space preceding PM 86        End If 87 88        ' convert hour from universal-time format to standard-time format 89        If (Hour = 12 OrElse Hour = 0) Then 90           standardHour = 12 91        Else 92           standardHour = Hour Mod 12 ' 1  through 11, AM or PM 93        End If 94 95        Return String.Format("{0}:{1:D2}:{2:D2} {3}",_ 96           standardHour, Minute, Second, suffix)        97     End Function ' ToString 98  End Class ' Time 

Figure 9.2. Graphical user interface for class Time.

  1  ' Fig. 9.2: FrmTimeTest.vb  2  ' Demonstrates Properties.  3  Public Class FrmTimeTest  4     Dim time As New Time() ' construct Time with zero arguments  5  6     ' invoked when user clicks the Add 1 to Second button  7     Private Sub btnAddSecond_Click(ByVal sender As System.Object, _  8        ByVal e As System.EventArgs) Handles btnAddSecond.Click  9        time.Second = (time.Second + 1) Mod 60 ' add 1 to Second 10        txtSetSecond.Text = time.Second 11 12        ' add one minute if 60 seconds have passed 13        If time.Second = 0 Then 14           time.Minute = (time.Minute + 1) Mod 60 ' add 1 to Minute 15           txtSetMinute.Text = time.Minute 16 17           ' add one hour if 60 minutes have passed 18           If time.Minute = 0 Then 19              time.Hour = (time.Hour + 1) Mod 24 ' add 1 to Hour 20              txtSetHour.Text = time.Hour 21           End If 22        End If 23 24        UpdateDisplay() ' update the text in lblOutput1 and lblOutput2 25     End Sub ' btnAddSecond_Click 26 27     ' handle event when txtSetHour's text changes 28     Private Sub txtSetHour_TextChanged(ByVal sender As System.Object, _ 29        ByVal e As System.EventArgs) Handles txtSetHour.TextChanged 30        time.Hour = txtSetHour.Text 31        UpdateDisplay() ' update the text in lblOutput1 and lblOutput2 32     End Sub ' txtSetHour_TextChanged 33 34     ' handle event when txtSetMinute's text changes 35     Private Sub txtSetMinute_TextChanged(ByVal sender As System.Object, _ 36        ByVal e As System.EventArgs) Handles txtSetMinute.TextChanged 37        time.Minute = txtSetMinute.Text 38        UpdateDisplay() ' update the text in lblOutput1 and lblOutput2 39     End Sub ' txtSetMinute_TextChanged 40 41     ' handle event when txtSetSecond's text changes 42     Private Sub txtSetSecond_TextChanged(ByVal sender As System.Object, _ 43        ByVal e As System.EventArgs) Handles txtSetSecond.TextChanged 44        time.Second = txtSetSecond.Text 45        UpdateDisplay() ' update the text in lblOutput1 and lblOutput2 46     End Sub ' txtSetSecond_Textchanged 47 48     ' update time display 49     Private Sub UpdateDisplay() 50        txtSetHour.Text = time.Hour 51        txtSetMinute.Text = time.Minute 52        txtSetSecond.Text = time.Second 53        lblOutput1.Text = ("Hour:" & time.Hour & "; Minute: " & _ 54           time.Minute & "; Second:" & time.Second) 55        lblOutput2.Text = ("Standard time is:" & time.ToString() & _ 56           "; Universal Time is:" & time.ToUniversalString()) 57     End Sub ' UpdateDisplay 58  End Class ' FrmTimeTest 

(a)

(b)

In Fig. 9.1, lines 34 begin the Time class declaration, indicating that class Time inherits from class Object of namespace System. Recall from Chapter 7 that it is not necessary to add an assembly reference for namespace System because it is implicitly added to all projects. Visual Basic programmers use inheritance to quickly create new classes from existing classes (and, as we will see in the next chapter, to organize groups of related classes). The Inherits keyword (line 4) followed by class name Object indicates that class Time inherits the attributes and behaviors of class Object. In fact, every class (except Object) inherits either directly or indirectly from Object. If you do not include line 4, the Visual Basic compiler includes it implicitly. A complete understanding of inheritance is not necessary to understand the concepts and programs in this chapter. We explore inheritance in detail in Chapter 10.

Lines 3 and 98 delimit with keywords Class and End Class, respectively, the body of the Time class declaration. Any information that we place in this body is contained within the class's scope. Class Time declares three Private Integer instance variableshour-Value, minuteValue and secondValue (lines 79)that represent the time in universaltime format (24-hour clock format). We prefer to list the instance variables of a class first, so that, when reading the code, you see the name and type of each instance variable before it is used in the class's methods.

It is possible to have Private methods and Public instance variables. Private methods are called utility methods, or helper methods, because they can be called only by other methods of the class to support the operation of those methods. Using Public instance variables in a class is an uncommon and dangerous programming practice. Providing such access to a class's instance variables is unsafe; other parts of the program could accidentally or maliciously set these members to invalid values, producing potentially disastrous results.

Time Class Properties

Class Time (Fig. 9.1) declares properties Hour (lines 2739), Minute (lines 4254) and Second (lines 5769) to access instance variables hourValue, minuteValue and secondValue, respectively. Each of these properties contains a Get accessor and a Set accessor. The Set accessors (lines 3238, 4753 and 6268) strictly control the setting of the instance variables to ensure that they contain valid values. An attempt to set any instance variable to an incorrect value causes the instance variable to be set to its default value12 (noon) for the hour and 0 for the minute and secondleaving the instance variable in a consistent state. Each Get accessor (lines 2830, 4345 and 5860) returns the appropriate instance variable's value.

Time Class Methods

Class Time contains the following Public methodsthe constructor New (lines 1315), SetTime (lines 1924), ToUniversalString (lines 7274) and ToString (lines 7797). Constructor New calls (in line 14) method SetTime (discussed shortly) with the hour value specified as 12, and the minute and second values specified as 0 to indicate that the default time should be noon. Visual Basic initializes Integer variables to 0 by default, so if we did not provide a constructor for class Time, instance variables hourValue, minuteValue and secondValue would each be initialized to 0, making the default time midnight. For some classes that would be fine, but we want our Time objects to be initialized to noon.

Constructors are implemented as Sub procedures, not as Functions, because Sub procedures cannot return values. Generally, constructors are declared Public. Private constructors are useful but are beyond the scope of the book. As we will see, a class can have many overloaded constructorsall share the same name, New, but each must have different numbers and/or types of parameters.

Method SetTime (lines 1924) uses properties Hour, Minute and Second to ensure that instance variables hourValue, minuteValue and secondValue have valid values. For example, the hourValue must be greater than or equal to 0 and less than 24, because universal-time format represents hours as integers from 0 to 23. Similarly, both the minuteValue and secondValue must fall between 0 and 59. Any values outside these ranges are invalid and default to 12 for the hourValue or 0 for the minuteValue and secondValue, ensuring that a Time object always contains valid data; that is, the object remains in a consistent state. When a user calls SetTime with invalid arguments, the program should indicate that the attempted time setting was invalid. This can be done by "throwing an exception"we discuss exception handling in Chapter 12.

Method ToUniversalString (lines 7274) takes no arguments and returns a String in universal-time format, consisting of the Hour property value, two digits for the Minute property value and two digits for the Second property value. For example, if the time were 1:30:07 PM, method ToUniversalString would return the String "13:30:07". Note that format specifier D2 formats a single digit integer value with a leading 0.

Method ToString (lines 7797) takes no arguments and returns a String in standard-time format, consisting of the Hour, Minute and Second property values separated by colons and followed by an AM or PM indicator (e.g., 1:27:06 PM). Lines 8293 determine the proper formatting for the hourhours from 0 to 11 print with AM, hours from 12 to 23 print with PM, hour 0 prints as 12 (midnight), hours 112 print as is and hours 1323 print as 111 (PM).

Note that method ToString contains the keyword Overrides (line 77) in its declaration. Recall that every class in Visual Basic (such as class Time) inherits either directly or indirectly from class Object, which is the root of the class hierarchy. Section 10.7 summarizes class Object's seven methods, including method ToString, which returns a String representation of an object. The default implementation of ToString that every class inherits (directly or indirectly) from class Object returns the namespace and the class name of the object's class. This implementation is primarily a placeholder that can be overridden by a derived class to specify a more appropriate String representation of the data in a derived class object. For class Time, we choose to override (i.e., redefine) the ToString method to return a String which represents the Time object in standard-time (i.e., 12-hour clock) format.

After defining the class, we can use it as a type in declarations such as

 Dim sunset As Time ' reference to object of class Time 


Using the Time Class

Class FrmTimeTest (Fig. 9.2) provides a GUI for testing class Time. The GUI contains three text boxes in which the user can enter values for the Time object's Hour, Minute and Second properties, respectively. Class FrmTimeTest creates an object of class Time (line 4) and assigns its reference to variable time. When the object is instantiated, New allocates the memory for the Time object, then calls the Time constructor (method New in lines 1315 of Fig. 9.1) to initialize the object's instance variables. The constructor invokes method SetTime of class Time to initialize each of the properties, setting the time to noon.

Common Programming Error 9.1

Using a reference (which, as you know, is initialized to the default value Nothing) before it refers to an actual object results in a NullReferenceException at execution time and causes the program to terminate prematurely. We discuss how to handle exceptions to make programs more robust in Chapter 12, Exception Handling.


Lines 2846 declare three methods that use the Time object's Hour, Minute and Second properties to alter the corresponding instance variable values. The GUI also contains a button that enables the user to increment the Second property value by 1 without having to use the corresponding text box. Method btnAddSecond_Click (lines 725) uses properties to determine and set the new time, ensuring that the values for the hour, minute and second are updated properly. For example, 23:59:59 becomes 00:00:00 when the user presses the button. Lines 5556 display the time in standard-time format (by invoking method ToString of Time) and universal-time format (by invoking method ToUniversalString of Time).

Note that we are able to use class Time in class FrmTimeTest (Fig. 9.2) even though there is no Imports statement to import class Time. Classes Time and FrmTimeTest are considered to be part of the same namespace by default because we placed then in the same project directory. In fact, every class and module in Visual Basic is part of a namespace. If you do not specify a namespace for a class or module, it is placed in the default namespace, which includes the compiled classes and modules in the current directoryin Visual Studio, this is a project's directory. When a class or module uses another class in the same namespace, an Imports statement is not required. The reason we must import the classes from the .NET Framework is that our classes and modules are in different namespaces from those in the .NET Framework. For console applications, Visual Studio automatically imports namespaces System, System.Data, System.Deployment and System.Xml. For Windows applications, Visual Studio automatically imports namespaces System, System.Deployment, System.Drawing and System.Windows.Forms.

Notes on the Time Class Declaration

Lines 79 of class Time (Fig. 9.1) declare instance variables hourValue, minuteValue and secondValue as Private. The Time constructor initializes the instance variable hourValue to 12 and the instance variables minuteValue and secondValue to 0 (i.e., noon) to ensure that the object is created in a consistent state. The instance variables of a Time object cannot contain invalid values, because they are Private, because the constructor (which calls SetTime) is called when the Time object is created, and because method SetTime uses properties to scrutinize all subsequent attempts by a client to modify the instance variables.

Methods ToUniversalString and ToString take no arguments because, by default, these methods manipulate the instance variables of the particular Time object for which they are invoked. Any method of a class can access all the instance variables of the class and can call every method of the class. This makes method calls more concise than conventional function calls in procedural programming. It also reduces the likelihood of passing the wrong arguments, the wrong types of arguments or the wrong number of arguments.

Software Engineering Observation 9.1

Using an object-oriented programming approach often simplifies method calls by reducing, or even eliminating, the arguments that must be passed. This benefit of object-oriented programming derives from the encapsulation of instance variables within an object.


Classes simplify programming because the clients of the class need be concerned only with its Public operations. Clients are neither aware of, nor involved in, a class's implementation. Interfaces change less frequently than implementations. When an implementation changes, implementation-dependent code must change accordingly. By hiding the implementation, we eliminate the possibility that the clients of the class will become dependent on the class's implementation details.

You do not always have to create classes from scratch. Rather, you can derive classes by inheritance from other classes that provide capabilities required by the new classes. Classes also can include references to objects of other classes as membersthis is called composition. Such software reuse can greatly enhance your productivity. Section 9.7 discusses composition. Chapter 10 discusses inheritance.



Visual BasicR 2005 for Programmers. DeitelR Developer Series
Visual Basic 2005 for Programmers (2nd Edition)
ISBN: 013225140X
EAN: 2147483647
Year: 2004
Pages: 435

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net