Using an interface
We have an interface. We have a class that implements it. Now for the tricky part: the code that actually uses the filter object. The Bug Wizard program has a control array of command buttons whose indexes correspond to the filter types in the EFilterType enum. The code to perform the appropriate filter action on a text file looks like this:
Private Sub cmdBug_Click(Index As Integer)
HourGlass Me
‘ CBugFilter part of object
Dim bug As CBugFilter
Set bug = New CBugFilter
‘ IFilter part of object
Dim filter As IFilter
Set filter = bug
‘ Set FilterType property on bug variable
bug.FilterType = Index
‘ Set Source property on filter variable
filter.Source = sFileCur
‘ Pass either variable to FilterTextFile
#If fOddDayOfTheMonth Then
FilterTextFile bug
#Else
FilterTextFile filter
#End If
HourGlass Me
End Sub
The HourGlass sub is a useful little procedure that displays
an hourglass cursor during an operation and then removes it.
Check it out in UTILITY.BAS. Always use a pair of HourGlass
procedures—the first to display the hourglass cursor and the
second to remove it.
If you’re like me, you might have to study this code for a few minutes before you get it. Notice that there’s only one object (because there’s only one New statement), but there are two object variables that refer to that object—and each object variable has a different type. You set the filter variable to the bug variable. This works because a CBugFilter is an IFilter (because it implements IFilter).
Next we set the properties. We set the FilterType of the bug object. We set the Source of the filter object. It wouldn’t work the other way around because a CBugFilter doesn’t have a Source, and an IFilter doesn’t have a FilterType. Notice that we use filter as if it had both public Source and Target properties, even though we know the real properties in CBugFilter are private and that their names are IFilter_Source and IFilter_Target.
When you get ready to pass the object to the FilterTextFile function, however, it doesn’t matter which object variable you pass because the FilterTextFile function is defined to take an IFilter parameter. You can pass the filter object variable because it has the same type as the parameter. But you can also pass the bug object variable because it is also an IFilter (because CBugFilter implements IFilter). It doesn’t work the other way around. An IFilter is not a CBugFilter. It’s the object itself, not the object variable, that has type CBugFilter. This is an interesting concept—an object with a different type than the object variable that references it.
I can’t say that I find this intuitive. The virtual method syntax used in most other object-oriented languages seems more intuitive. But the syntax grows on you the more you use it.
I do have one complaint. Visual Basic lacks class type casting. Most object-
oriented languages allow you to cast the outer type to the inner type. Instead of creating a separate filter variable, you could cast the bug variable to an IFilter like this:
‘ Set Source property on filter part
IFilter(bug).Source = sFileCur
Chapter 10 will tell how to fake this syntax.