Introduction to Class Programming in Visual Basic
In our previous discussion, we tackle about the basic concepts of class,
including creating it's state (property) and behavior (methods).
We also discuss about simple validation of its class property by including
validation code in its Property Let. Thus making your class more
robust. We also discuss about some property variation, such as
read-only property as well as write-only property. We also discuss
decision making of using function (method) and property procedure in your class.
In this series articles, we are going to discuss about: Enumeration, Properties that return an Object and
other semi-advance topic pertain to in creating a class base program.
Enumerated Properties
An enumeration allows you to define your own set of named constants. A named
constant is an item that preserve a constant value throughout the execution of a
program and can be used in place of literal values. In other words, an Enum
is nothing but a group of related constant values that
automatically take different values. You can use named constants as
property values, method arguments, and as a function's return values. By using a named
constant it makes your code easier to read and maintain. For example, some
properties are intended to return a well-defined subset of integer numbers. In
our Student class, we can implement a YearLevel property that can
be assigned the values 1 (Freshmen), 2 (Sophomore), 3 (Junior), and 4
(Senior).
' In the declaration section of the class
Enum YearLevelEnum
Freshmen = 1
Sophomore
Junior
Senior
End Enum
|
You don't need to assign an explicit value to all the items in the Enum
structure, Visual Basic increments the preceding value automatically by 1. But because 0 is the
default value for any Integer property when the class is created, Visual Basic
starts at 0. It is a good programming style that you should always stay clear in
assigning value to the enum list, so that you can later trap any value that
hasn't been properly initialized . But Enum values don't need to be
in an increasing sequence. In fact, you can provide special values for Enum
constant list, as shown below:
' In the declaration section of the class
Enum GradeEnum
Falling = 50
Passing = 75
Probationary = 84
Except = 90
End Enum
|
After you define an Enum structure, you can create a Public or
Private
property
of the corresponding type:
Private m_YearLevel As YearLevelEnum
Property Get YearLevel() As YearLevelEnum
YearLevel= m_YearLevel
End Property
Property Let YearLevel(ByVal enumValue As YearLevelEnum)
' Refuse invalid assignments.
If enumValue <= 0 Or enumValue > Senior Then Err.Raise 5
m_YearLevel= enumValue
End Property
|
You should never forget that Enums are just shortcuts
for creating constants. This means that all the enumerated constants defined
within an Enum block should have unique names in their scope. Typically Enums
type are made by programmer to be Public, so their scope is often the
entire application.
It is a good programming practice, that you should devise a method for
generating unique names for all your enumerated constants. If you fail to do
that, the compiler refuses to compile your application and raises the
"Ambiguous name detected: " error. The easy way to
avoid this problem is to add to all the enumerated constants a unique 2 or 3
letter prefix, for example:
' In the declaration section of the class
Enum YearLevelEnum
lvlFreshmen = 1
lvlSophomore
lvlJunior
lvlSenior
End Enum
|
Another way to avoid ambiguous name problem is use the complete enumname.constantname
syntax whenever you refer to an ambiguous Enum member, as in the
following code:
Student.YearLevel = YearLevelEnum.lvlSenior
|
While enumerated properties are very useful and allow you to store some
descriptive information in just 4 bytes of memory, sooner or later you will have to extract and
decode this information and
sometimes even show it to your users. For this reason, It is a good programming
practice to add a read-only property that returns the
description of an enumerated property:
Property Get YearLevelDescription() As String
Select Case m_YearLevel
Case lvlFreshmen : YearLevelDescription = "Freshmen"
Case lvlSophomore: YearLevelDescription = "Sophomore"
Case lvlJunior: YearLevelDescription = "Junior"
Case lvlSenior: YearLevelDescription = "Senior"
Case Else: Err.Raise 5
End Select
End Property
|
Another issue that you should never forget that your class are often change its structure if
you are still in developing stage. So it is possible that your validation code
can become outdated. For example, what happens if you later add a fifth YearLevel
constant such Graduate or Masteral? For this reason, you should always add
new constants safely without modifying the validation code in the
corresponding Property Let procedure, one way to do this is create a enum constant as the highest value in that block and assign
the value that you wanted to be the last enum constant, as shown below:
' In the declaration section of the class
Enum YearLevelEnum
lvlFreshmen = 1
lvlSophomore
lvlJunior
lvlSenior
lvlGraduate ' newly added enum constant
lvlMasteral ' newly added enum constant
YEAR_LEVEL_MAX = lvlMasteral ' make lvlMasteral the last enum constant
End Enum
Property Let YearLevel(ByVal enumValue As YearLevelEnum)
' Refuse invalid assignments
If enumValue <= 0 Or enumValue > YEAR_LEVEL_MAX Then Err.Raise 5
m_YearLevel= enumValue
End Property
|
As you can see we can safely add a new enum constant without worrying
about the validation code in our Property Let to become obsolete. And
making our maximum value in uppercase and putting a comment, we
can easily spot it in our source code. Of course, you should account your
read-only property description, because adding new enum constant in
our enum block without adding appropriate description our YearLevelDescription
property will result to an error, but at least we are safely notified.
' Modified version
Property Get YearLevelDescription() As String
Select Case m_YearLevel
Case lvlFreshmen: YearLevelDescription = "Freshmen"
Case lvlSophomore: YearLevelDescription = "Sophomore"
Case lvlJunior: YearLevelDescription = "Junior"
Case lvlSenior: YearLevelDescription = "Senior"
Case lvlGraduate: YearLevelDescription = "Graduate"
Case lvlMasteral: YearLevelDescription = "Masteral"
Case Else: Err.Raise 5
End Select
End Property
|
The addition of highest value for your enum list might confuse your
user. You might want to hide this or decided not to show it from your user
when they started to use your class. I common technique that you can use
is by placing an underscore at the start of the enum list identifier as
shown below:
Enum GenderEnum
Male = 1
Female
[_GENDER MAX] = Female
End Enum
|
The square brackets [] are necessary because, Visual Basic will complain by raising
a compile error: Invalid character. Adding square brackets permit
us to add an underscore ( _ )at
the beginning of the enum list identifier and brought
us another useful technique, you can now add space to your enum list
identifier as shown above. Unfortunately, even you, the author of the
class cannot see this! So you must remember this enum list
identifier when you use your class, especially in the Property procedures
validation code.
One last thing that I can add pertaining to enumerated type. Sometimes, you need this description to populate a control in you
client form, such as ComboBox and ListBox control. One technique that
I used
frequently, I usually change the implementation of description property by
adding an optional ByVal parameter and then use the textual description
to populate the control:
' In the Student class module
Public Sub LoadYearLevelDescriptionTo(ctrl As Control)
Dim i As Integer
ctrl.Clear
For i = Freshmen To [_YEAR LEVEL MAX]
ctrl.AddItem YearLevelDescription(i)
Next i
End Sub
Property Get YearLevelDescription(Optional ByVal level As YearLevelEnum) As String
Dim tempLevel As Long
' If argument level contain a value, use it in the Select Case,
' otherwise, use the Private m_YearLevel variable
tempLevel = IIf(level = 0, m_YearLevel, level)
Select Case tempLevel
Case Freshmen: YearLevelDescription = "Freshmen"
Case Sophomore: YearLevelDescription = "Sophomore"
Case Junior: YearLevelDescription = "Junior"
Case Senior: YearLevelDescription = "Senior"
Case Graduate: YearLevelDescription = "Graduate"
Case Masteral: YearLevelDescription = "Masteral"
Case Else: Err.Raise 5
End Select
End Property
' In your client form
' Load Year level description in ListBox Control
Student.LoadYearLevelDescriptionTo List1
or
' Load Year level description in ListBox Control
Student.LoadYearLevelDescriptionTo Combo1
|
See, how easy it would be in the client, I don't have to populate the List
property of the Combo or ListBox control in the client form, all I
have to do is to call LoadYearLevelDescriptionTo to do the work.
Note, you can still use the Property YearLevelDescription without an argument:
' Return the Year Level Description of this particular Student
Debug.Print Student.YearLevelDescription
|
Object Properties
In addition to (enumerated) class properties, our class objects might expose
properties that return object values. To give you an example, Visual Basic
object such as forms and visible controls expose a Font property, which
returns a Font object.
txtFirstName.Font.Name = "Tahoma"
txtFirstName.Size = 10
txtFirstName.Bold = True
frmStudent.Font.Bold = True
|
We can also do this in our classes. Taking our Student class, we might
add a Address property, but string is not enough to point accurately
where the student lives, and we usually need several pieces of related
information, such street, city, state or province, zip
code, as well as country. Instead of adding multiple properties
to the Student object, create a new Address class:
- To create an Address class
- On the Project menu, click Add Class Module.
- In the Add Class Module dialog box, select Class Module,
then click Open.
- In the Properties window, set the Name property for the
class module to Address.
- In the Code window, type the following:
Option Explicit
' In Address class module declaration
Private m_Street As String
Private m_City As String
Private m_State As String
Private m_Zip As String
Private m_Country As String
Public Property Let Street(ByVal strNewStreet As String)
If Len(strNewStreet) = 0 Then Err.Raise 5
m_Street = strNewStreet
End Property
Public Property Get Street() As String
Street = m_Street
End Property
Public Property Let City(ByVal strNewCity As String)
If Len(strNewCity) = 0 Then Err.Raise 5
m_City = strNewCity
End Property
Public Property Get City() As String
City = m_City
End Property
Public Property Let State(ByVal strNewState As String)
If Len(strNewState) = 0 Then Err.Raise 5
m_State = strNewState
End Property
Public Property Get State() As String
State = m_State
End Property
Public Property Let Zip(ByVal strNewZip As String)
If Len(strNewZip) = 0 Then Err.Raise 5
m_Zip = strNewZip
End Property
Public Property Get Zip() As String
Zip = m_Zip
End Property
Public Property Let Country(ByVal strNewCountry As String)
If Len(strNewCountry) = 0 Then Err.Raise 5
m_Country = strNewCountry
End Property
Public Property Get Country() As String
Country = m_Country
End Property
Public Function CompleteAddress() As String
CompleteAddress = Street & vbCrLf & _
City & ", " & State & " " & Country & " " & Zip
End Function
|
Now you can add our new Address property to our Student class
in declaration section of the Student class module:
'In the declaration section of the Student class module
'Enum type declaration omitted
Private m_Student_ID As String
Private m_FirstName As String
Private m_LastName As String
Private m_MajorCode As MajorCodeEnum
Private m_YearLevel As YearLevelEnum
Private m_BirthDate As Date
Private m_Gender As GenderEnum
Private m_Address As Address ' Student address
|
Property Set procedures
A Property Set procedure sets the value of a property that contains a
reference to an object. When you assign a value to an object, you must use the
Visual Basic Set statement. An example of a property which is an
object itself would be the Font property of the TextBox control. Because you're
dealing with object references, you must use the Set keyword in both
procedures. Add the following property procedure and additional method, as well
as the revised version of StudentInfo method in Student class module:
' Student Address property procedures
Property Get Address() As Address
Set Address = m_Address
End Property
Property Set Address(ByVal strNewAddress As Address)
Set m_Address = strNewAddress
End Property
' New Student method
Function StudentAddressInfo() As String
If m_Address Is Nothing Then Err.Raise 5
StudentAddressInfo = m_Address.CompleteAddress
End Function
' Student StudentInfo method revised
Function StudentInfo(Optional ByVal IncludedAddressInfo As Boolean = True) As String
' Returns the Student information
Dim info As String
info = "Student # : " & StudentID & vbCrLf & _
"Name : " & FullName & vbCrLf & _
"Age : " & Age & vbCrLf & _
"Gender : " & GenderDescription & vbCrLf & _
"Major Code : " & MajorCode & vbCrLf & _
"Major Description: " & MajorCodeDescription & vbCrLf & _
"Year Level : " & YearLevelDescription
If IncludedAddressInfo Then info = info & "Address : " & StudentAddressInfo()
StudentInfo = info
End Function
|
In our new StudentAddressInfo
method, it is a good programming practice that you check first the existence of
an object (Address) with in an object (Student), because a call to
that method will raise an error number 91.
Now you can create a Address object in client form, initialize its
properties, and then assign it to the Address property of the Student
object.
' In client form
' Declare Student object and Address Object
Dim Student As Student
Dim Address As Address
' Initiate the object Student
Set Student = New Student
' Initiate the object Address
Set Address = New Address
' Set up Address properties
With Address
.Street = "Block 10 Lot 26, Molave Street, Calendola Village"
.City = "San Pedro"
.State = "Laguna"
.Country = "Philippines"
.Zip = "4023"
End With
' Set up Student pproperties
With Student
.FullName = "Dante Salvador"
' Add the newly created Address object to Student Address property
Set .Address = Address
.StudentID = "102472"
.BirthDate = #10/24/1972#
.Gender = Male
.YearLevel = Senior
.Major = BSCS
End With
' Show Student information
MsgBox Student.StudentInfo
|
Variant Properties
You can add flexibility to your class by including a Variant member.
Assuming that you want to implement a ProvincialAddress property, but you
want to keep it more flexible and capable of storing either a Address
object or a string. Now let us add ProvincialAddress property
to our Student class as shown below:
Private m_ProvincialAddress As Variant
Property Get ProvincialAddress() As Variant
If IsObject(m_ProvincialAddress) Then
Set ProvincialAddress = m_CurrentAddress ' Return a Address object.
Else
ProvincialAddress = m_ProvincialAddress ' Return a string.
End If
End Property
Property Let ProvincialAddress(ByVal strNewProvincialAddress As Variant)
m_ProvincialAddress = strNewProvincialAddress
End Property
Property Set ProvincialAddress(ByVal strNewProvincialAddress As Variant)
Set m_ProvincialAddress = strNewProvincialAddress
End Property
' Revised StudentInfo method
Function StudentInfo(Optional ByVal IncludeAddressInfo As Boolean = True, _
Optional ByVal IncludeProvincialAddressInfo As Boolean = False) As String
' Returns the Student information
Dim info As String
info = "Student # : " & StudentID & vbCrLf & _
"Name : " & FullName & vbCrLf & _
"Age : " & Age & vbCrLf & _
"Gender : " & GenderDescription & vbCrLf & _
"Major Code : " & MajorCode & vbCrLf & _
"Major Description: " & MajorCodeDescription & vbCrLf & _
"Year Level : " & YearLevelDescription
If IncludeAddressInfo Then info = info & vbCrLf & "Address : " & StudentAddressInfo()
If IncludeProvincialAddressInfo Then info = info & vbCrLf & "Provincial Add : " & _
StudentProvincialAddInfo()
StudentInfo = info
End Function
' Newly added method for Student class
Function StudentProvincialAddInfo() As String
' Return Student Provincial address
If IsObject(m_ProvincialAddress) Then
' invoke Address CompleteAddress method
StudentProvincialAddInfo = m_ProvincialAddress.CompleteAddress
Else
' simply return a string
StudentProvincialAddInfo = m_ProvincialAddress
End If
End Function
|
But things are a bit more complex if the property can receive either a
regular value or an object value. While this sort of flexibility adds a lot of power to your class, it also
reduces its robustness because nothing keeps a programmer from adding a
nonstring value or an object of a class other than Address:
'In the client form
With Student
.FullName = "Dante Salvador"
Set .Address = 12345 ' an Integer value
.StudentID = "102472"
'etc
End With
|
Because ProvincialAddress property is declared as Variant type,
meaning you can assign any value, including numeric type. To have more
control of what is actually assigned to this property, you need to arbitrate all
accesses to it through Property procedures:
' In Student class module
' Revised property procedures
Property Let ProvincialAddress(ByVal strNewProvincialAddress As Variant)
' Check if it is a string value.
If VarType(strNewProvincialAddress) <> vbString Then Err.Raise 5
m_ProvincialAddress = strNewProvincialAddress
End Property
Property Set ProvincialAddress(ByVal strNewProvincialAddress As Variant)
' Check if it is a Address object.
If TypeName(strNewProvincialAddress) <> "Address" Then Err.Raise 5
Set m_ProvincialAddress = strNewProvincialAddress
End Property
'In the client form
With Student
.FullName = "Dante Salvador"
Set .Address = 12345 ' this raises an error
.StudentID = "102472"
'etc
End With
|
Another technique that you can use that give slightly improve run-time
performances and you save some code is to declare the type of the object you're expecting
right in the parameter list of the Property Set procedure:
Property Set ProvincialAddress(ByVal strNewProvincialAddress As Address)
' Check if it is a Address object.
If TypeName(strNewProvincialAddress) <> "Address" Then Err.Raise 5
Set m_ProvincialAddress = strNewProvincialAddress
End Property
|
But you can't use
it when if your class accept two or more objects of different types. One
solution is use As Object parameter:
Property Set ProvincialAddress(ByVal strNewProvincialAddress As Object)
If TypeName(strNewProvincialAddress) <> "Address" And _
TypeName(strNewProvincialAddress) <> "OtherAddressType" Then Err.Raise 5
Set m_CurrentAddress = newValue
End Property
|
Object Keyword
The TypeName function
The TypeName function returns the name of an object's class in
the form of a string. This means that you can find the type of an object
in a more concise form
In many situations, testing an object's type using the TypeName
function is preferable to using the TypeOf...Is statement because
it doesn't require that the object class be present in the current
application or in the References dialog box. For information about
TypeOf...Is function, consult your Visual Basic documentation.
The VarType function
The VarType function returns the type name of an object's
class in the form of a string. Variant variables can also host special
values that don't correspond to any data values described so far. The Empty
value is the state of a Variant variable when nothing has been
assigned to it yet. You can test this special value using the IsEmpty
function, or you can test the VarType function for the value
0-vbEmpty.
The Null value is useful in database programming to mark fields that
don't contain a value. You can explicitly assign the Null value to a
Variant using the Null constant, test for a Null value using the IsNull
function, or compare the return value of the VarType function
with the value 1-vbNull. For more information about this function,
consult your Visual Basic documentation.
|
Advanced Uses 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 the Class_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
|
Reference:
Visual Basic Help Online: Microsoft Corporation
Still to Come
In the next article, We're going to discuss about Collection Classes