|
||||||||||||||||||||||||
| You are on the Home/Publications & Training/Case Studies/Property procedures in a standard module page |
Case Study – Property procedures in a standard moduleThose readers familiar with the use of objects in VB(A) know about the three Property procedures (Get, Let, and Set). The typical use of these procedures is to create a property in the class. The consumer of the class can then interrogate or assign a value to the property. What most people may not be aware of is that one can use property procedures in standard modules! As in the case of a class module, a property behaves like a variable but in a far more complex manner. The major advantage of a property over a public variable is that one can do a lot more than provide the consumer of the variable unfettered access to the raw value. For example, suppose one wants to create a variable that holds one of the three primary computer colors – red, green, or blue – and no other color. In a standard module named ColorManager one could create Option Explicit Option Private Module Public lPrimaryColor As Long 'only legitimate values are R, G, or B The major downside of this approach is that there is no way to enforce that lPrimaryColor contains only of the three legitimate values, RGB(255,0,0), RGB(0,255,0), or RGB(0,0,255). In another module, say, ColorConsumer, code like that below would work just fine even though it violates the intent of lPrimaryColor. Sub unfetteredVariableAccess() lPrimaryColor = RGB(128, 0, 0) MsgBox lPrimaryColor End Sub Implement and use property procedures in a standard moduleAn alternative – and far more robust – approach would be to change the ColorManager standard module to: Option Explicit Option Private Module Dim lPrimaryColor As Long Property Get PrimaryColor() As Long PrimaryColor = lPrimaryColor End Property Property Let PrimaryColor(uPrimaryColor As Long) Select Case uPrimaryColor Case Is = RGB(255, 0, 0), RGB(0, 255, 0), RGB(0, 0, 255): lPrimaryColor = uPrimaryColor Case Else: lPrimaryColor = 0 End Select End Property |
|
||||
|
The code above declares a property PrimaryColor with a paired Get and Let procedures. Effectively, and just as in a class module, the use of the two property procedures creates something that others can use as though it were a single variable! This impacts consumers, such as ColorConsumer, in two related ways. The first is because ColorManager is a private module and lPrimaryColor is no longer a public variable. Consequently, ColorConsumer can no longer directly access the variable. The code in the unfetteredVariableAccess subroutine above would generate a compile error: Variable not declared. The second is that PrimaryColor can now be treated as a variable. Suppose ColorConsumer has the following procedure: Sub testPropInOtherModule() PrimaryColor = RGB(255, 0, 0): MsgBox PrimaryColor PrimaryColor = RGB(0, 255, 0): MsgBox PrimaryColor PrimaryColor = RGB(0, 0, 255): MsgBox PrimaryColor PrimaryColor = RGB(128, 0, 0): MsgBox PrimaryColor End Sub The above code is perfectly valid and will execute as expected. The last assignment (of a non-primary color to the PrimaryColor changes it to black, i.e., RGB(0,0,0). Since the property behaves like a variable of a particular data type, one can use it just one would use a variable of that data type. Since the PrimaryColor property is defined as a long (see the Get procedure), one can use it as though it were a simple variable of type Long as in the example below. The rotatePrimaryColor subroutine rotates the PrimaryColor property through its three legitimate values first with a complex IF statement and then nested IIf functions. In each instance, an uninitialized property becomes red. Sub rotatePrimaryColor() If PrimaryColor = RGB(255, 0, 0) Then PrimaryColor = RGB(0, 255, 0) ElseIf PrimaryColor = RGB(0, 255, 0) Then PrimaryColor = RGB(0, 0, 255) Else PrimaryColor = RGB(255, 0, 0) End If MsgBox PrimaryColor PrimaryColor = IIf( _ PrimaryColor = RGB(255, 0, 0), RGB(0, 255, 0), _ IIf(PrimaryColor = RGB(0, 255, 0), RGB(0, 0, 255), _ RGB(255, 0, 0))) MsgBox PrimaryColor End Sub The use of the property PrimaryColor can – and should – be extended to the ColorManager module itself. The developer of the ColorManager module should exhibit the same discipline that the developer of a class module must exhibit and resist the temptation to directly access variables associated with properties. One can easily make the rotatePrimaryColor subroutine above a public sub in the ColorManager module (essentially the equivalent of a method of a class). Of course, now that the subroutine is in the same module as the lPrimaryColor variable, it would have direct access to the variable. However, basic defensive programming requires that the developer limit herself to the PrimaryColor property. Put the code below in the ColorManager module Public Sub rotatePrimaryColor() PrimaryColor = IIf( _ PrimaryColor = RGB(255, 0, 0), RGB(0, 255, 0), _ IIf(PrimaryColor = RGB(0, 255, 0), RGB(0, 0, 255), _ RGB(255, 0, 0))) End Sub Now, in the consumer module, ColorConsumer, one could have code like: Sub testRotateColors() rotatePrimaryColor MsgBox PrimaryColor rotatePrimaryColor MsgBox PrimaryColor rotatePrimaryColor MsgBox PrimaryColor rotatePrimaryColor MsgBox PrimaryColor End Sub SummaryThis tip demonstrated that the use of a property is not restricted to a class module. The same developer advantages enjoyed by the use of a property in a class module also apply to its use in a standard module.
|
|||||