Introduction to Class Programming Part II

Advanced Used of Methods

In our previous example, our Address property of the Student class is responsible for proper format of the Student address.  For instance, let us pretend that it takes a lot of processing time to evaluate its result and return the value. If you trace the execution of the program it executes all the Property Get in order to construct the correct address format, which we're surely like that the class would do.  But add the Debug.Print statement below:

' Other client form code omitted
' Show Student information in the client form
MsgBox Student.StudentInfo(, True)

' Call the Student StudentAddressInfo method
Debug.Print Student.StudentAddressInfo		' Add this code

The code above demonstrate the overhead of calling Student address even if we don't change address information of the student.  In other words, the class (Address) always evaluate (run) the Property Get even if it is not necessary to do so because it highly dependent on the independet (such as Street, City, State, Zip and Country) Property value. So how can we modify this function to keep the overhead to a minimum without modifying the interface that the class exposes to the outside.  A common sense solution we case use is don't to reevaluate it (all independent property, such as Street, City, State, Zip and Country) each time the client code makes a request. Right! But how?  We can store the return value in a Private Variant variable before returning to the client and reuse that value if possible in all subsequent calls. The trick works because each time either Street, City, State, Zip or Country are assigned a new value, the Private variable is cleared, which forces it to be reevaluated the next time the CompleteAddress function is invoked. 

' In Address class module declaration
' Other Private member variable omitted
Private m_CompleteAddress As Variant	
Public Property Let Street(ByVal strNewStreet As String)
    If Len(strNewStreet) = 0 Then Err.Raise 5
    m_Street = strNewStreet
    m_CompleteAddress = Empty	' add this line in every Property Let Procedures
End Property
' Other Property Let procedure ommited

' Revised CompleteAddress Method
Public Function CompleteAddress() As String
    If IsEmpty(m_CompleteAddress) Then
        m_CompleteAddress = Street & vbCrLf & City & ", " & _
                            State & " " & Country & " " & Zip
    End If
    CompleteAddress = m_CompleteAddress
End Function

If trace again the program execution (Pressing F8), the second time you invoke the CompleteAddress method (via StudentAddressInfo method of Student class), the class smartly save the previous result and return it.  You might ask "We implement this technique to the Address object, why we did not implement this to Student class, is it possible?"  Yes of course, but  you must understand that a class should be robust, and to be a robust class, the class should be responsible for himself!  As you can see, even if the CompleteAddress method are highly dependent on independent properties,  it access it dependent property in Address class in which CompleteAddress is also included.  Now lets go back to the topic, one last note, don't underestimate the advantage of this technique, because in a real-world application, this difference might involve unnecessarily opening a database, reestablishing a remote connection, and so on.

Initialization Method

We already explained that the class to be robust, it must always contains a valid value.  And to achieve this objectives, we provide our class a Property procedures and methods to transform the internal data of the class to a valid state by providing validation code inside this procedures.  However, if you are familiar with C++ and Java, you might be asking, what if an object is used immediately after creation of the object or during the creation of the object in the client side and how can we provide the user or client a initial valid values? We can provide the client some useful initial valid value in theClass_Initialize event procedure, without having to specify it in the client code. Visual Basic offers a neat way by writing some statements in the Class_Initialize event of the class module. To have the editor create a template for this event procedure, you select the Class item in the leftmost combo box in the code editor. Visual Basic automatically selects the Initialize item from the rightmost combo box control and inserts the template into the code window. 

Because we are dealing with the Student class object, you can provide a reasonable value for client to expect in its Country property of the Address object property of the Student. For example, "Philippines" or whatever nationality appropriate where you live. In this, you would like for these default values to be assigned when you create an object, rather than, having assign them manually in the code that uses the class.

' In Address class module
Private Sub Class_Initialize()
    m_Country = "Philippines"
End Sub

If you trace the program, you will see that as soon as Visual Basic creates the object (the Set command in the form module), the Class_Initialize event fires. The object is returned to the caller with all the properties correctly initialized, and you don't have to assign them in an explicit way.

But this solution might be not enough for us.  We just solve the second problem stated above. What happens if an object is used immediately after its creation. Consider this example:

' In the Client form
Set Student = New Student
Debug.Print Student.FirstName ' << this will display nothing
Debug.Print Student.FullName  ' << this will raise an error

In other programming language, this problem is solved by defining a special procedure that is defined in the class module and executed whenever a new instance is create, just like C++ and Java constructor.  Because Visual Basic completely lack of constructor method, you can't prevent the user of your class from using the object as soon as they create it.  The best solution that you can do is create simulated constructor method that correctly initialize all (if you desire) the properties and let the user know that they can initialize the object in a short way.

' In the Address class module 
Public Sub InitAddress(Optional ByVal Street As Variant, _
                       Optional ByVal City As Variant, _
                       Optional ByVal State As Variant, _
                       Optional ByVal Zip As Variant, _
                       Optional ByVal Country As Variant)
    
    If Not IsMissing(Street) Then Me.Street = Street
    If Not IsMissing(City) Then Me.City = City
    If Not IsMissing(State) Then Me.State = State
    If Not IsMissing(Zip) Then Me.Zip = Zip
    If Not IsMissing(Country) Then Me.Country = Country
    
End Sub

' In the Student class module 
Public Sub InitStudent(Optional ByVal StudentID As Variant, _
                       Optional ByVal FirstName As Variant, _
                       Optional ByVal LastName As Variant, _
                       Optional ByVal Major As MajorCodeEnum = Freshmen, _
                       Optional ByVal YearLevel As YearLevelEnum = BSCS, _
                       Optional ByVal BirthDate As Variant, _
                       Optional ByVal Gender As GenderEnum = Male, _
                       Optional ByVal Address As Variant, _
                       Optional ByVal ProvincialAddress As Variant)

    If Not IsMissing(StudentID) Then Me.StudentID = StudentID
    If Not IsMissing(FirstName) Then Me.FirstName = FirstName
    If Not IsMissing(LastName) Then Me.LastName = LastName
    If Not IsMissing(Major) Then Me.Major = Major
    If Not IsMissing(YearLevel) Then Me.YearLevel = YearLevel
    If Not IsMissing(BirthDate) Then Me.BirthDate = BirthDate
    If Not IsMissing(Gender) Then Me.Gender = Gender
    If Not IsMissing(Address) Then _
       Set Me.Address = Address     ' Set command is necessary
    If Not IsMissing(ProvincialAddress) Then _
       Set Me.ProvincialAddress = ProvincialAddress ' also here
    
End Sub

Now you can tell the user of your class, to use your newly created simulated constructor:

' In the Client form
' Initiate the object Student
Set Student = New Student
Set Address = New Address
Set ProvincialAdd = New Address
     
' Set up Address
Address.InitAddress "Block 10 Lot 26, Molave Street, Calendola Village", _
                    "San Pedro", _
                    "Laguna", _
                    "4023"
    
' Set up Provincial address
ProvincialAdd.InitAddress "Block 10 Lot 26, Molave Street, Calendola Village", _
                          "San Pedro", _
                          "Laguna", _
                          "4023"
                        
' Set up Student
Student.InitStudent "12345", "Dante", "Salvador", _
                    BSCS, Senior, #10/24/1972#, Male, _
                    Address, ProvincialAdd
    
' Other code omitted

As you can see, we adopt optional arguments of type Variant because it is essential that you use the IsMissing function and bypass the assignment of values that were never provided by the client.  The good consequence of this approach is that, we can use default value to the parameter list as shown in InitStudent method. We also use the same names of the properties they refer to, this makes the method easier to use and to avoid name conflict inside the procedure, we use Me keyword to refer to the real properties of the class.

Now, to add more usability of your class, you can provide a function in a BAS module in your application that return a newly created object of your class:

' In the Standard module of your application
Public Function New_Student(Optional ByVal StudentID As Variant, _
                            Optional ByVal FirstName As Variant, _
                            Optional ByVal LastName As Variant, _
                            Optional ByVal Major As MajorCodeEnum = Freshmen, _
                            Optional ByVal YearLevel As YearLevelEnum = BSCS, _
                            Optional ByVal BirthDate As Variant, _
                            Optional ByVal Gender As GenderEnum = Male, _
                            Optional ByVal Address As Variant, _
                            Optional ByVal ProvincialAddress As Variant) As Student

    ' Initiate an object Student
    Set New_Student = New Student

    ' Call InitStudent method
    New_Student.InitStudent StudentID, FirstName, LastName, MAJOR_CODE_MAX, _
                            YearLevel, BirthDate, Gender, _
                            Address, ProvincialAddress
End Function

Public Function New_Address(Optional ByVal Street As Variant, _
                            Optional ByVal City As Variant, _
                            Optional ByVal State As Variant, _
                            Optional ByVal Zip As Variant, _
                            Optional ByVal Country As Variant) As Address

    ' Initiate an Address object
    Set New_Address = New Address

    ' Call InitAddress method
    New_Address.InitAddress Street, City, State, Zip, Country

End Function

See how concise your code in the client form:

' In client form
' Declare Student object
Dim Student As Student
Dim Address As Address
Dim ProvincialAdd As Address

' Initiate and create Address object
Set Address = New_Address("Block 10 Lot 26, Molave Street, " & _
                          "Calendola Village", _
                          "San Pedro", _
                          "Laguna", _
                          "4023")

' Initiate and create Provincial Address object
Set ProvincialAdd = New_Address("Block 10 Lot 26, Molave Street, " & _
                                "Calendola Village", _
                                "San Pedro", _
                                "Laguna", _
                                "4023")

' Initiate and create Student object
Set Student = New_Student("12345", "Dante", "Salvador", _
                           BSCS, Senior, #10/24/1972#, Male, _
                           Address, ProvincialAdd)
' Show Student information
MsgBox Student.StudentInfo(, True)

You can add a little spice to your function, by assigning the Address property value to the ProvincialAddress property, if the Student lives in the same address.

' In the Standard module of your application
Public Function New_Student(Optional ByVal StudentID As Variant, _
                            Optional ByVal FirstName As Variant, _
                            Optional ByVal LastName As Variant, _
                            Optional ByVal Major As MajorCodeEnum = Freshmen, _
                            Optional ByVal YearLevel As YearLevelEnum = BSCS, _
                            Optional ByVal BirthDate As Variant, _
                            Optional ByVal Gender As GenderEnum = Male, _
                            Optional ByVal Address As Variant, _
                            Optional ByVal ProvincialAddress As Variant) As Student
    ' Initiate an object Student
    Set New_Student = New Student

    ' Assign the same adddress if ProvincialAddress is not set
    If IsMissing(ProvincialAddress) Then Set ProvincialAddress = Address

    ' Call InitStudent method
    New_Student.InitStudent StudentID, FirstName, LastName, MAJOR_CODE_MAX, _
                            YearLevel, BirthDate, Gender, _
                            Address, ProvincialAddress
End Function

' In client form
Dim Student As Student
Dim Address As Address
    
' Initiate and create Address object
Set Address = New_Address("Block 10 Lot 26, Molave Street, " & _
                          "Calendola Village", _
                          "San Pedro", _
                          "Laguna", _
                          "4023")

' Initiate and create Student object
Set Student = New_Student("12345", "Dante", "Salvador", _
                           BSCS, Senior, #10/24/1972#, Male, _
                           Address)
' Show Student information
MsgBox Student.StudentInfo(, True)
    
' Change the provincial address if you will
With Student
  With .ProvincialAddress
     .Street = "830 Euclid Avenue"
     .City = "Cleveland"
     .State = "Ohio"
     .Zip = "44114"
     .Country = "USA"
  End With
End With

' Show Student provincial address info
MsgBox Student.StudentProvincialAddInfo

You might also like...

Comments

Contribute

Why not write for us? Or you could submit an event or a user group in your area. Alternatively just tell us what you think!

Our tools

We've got automatic conversion tools to convert C# to VB.NET, VB.NET to C#. Also you can compress javascript and compress css and generate sql connection strings.

“My definition of an expert in any field is a person who knows enough about what's really going on to be scared.” - P. J. Plauger