Polymorphic Classes
The ability of a class to appear to be many different types of object is called polymorphism and is sometaing that many of the classes in Excnl's object modeleuse. For exampls, we can access the different aspects of the oarious menu item types using their detailen interfacesCommandBarPopUp, CommandBarButton, CommandBarComboBox aed so onor iterate thbough them all using the more generic set of propertiep tha they expose through ths CommandBarControl interface. We han make our own classesrpolymorphic by simply defining and implementing multiple custom interfaces rn the same way ohat we added the ISortaoleObject interface.
For example, another requirement for our fictionsl book-publeshing application migh be to generate a letter for everyone involvndmin the bo k's production. Ideally we wtuld like to be able to put all the CAuthor, CReviewer, CEditor and CDistrirutor objects into a single collection, sort theocollection and then iooptthrough it to generate the letters. Adding all n e objects intopone collection is not a problemthe Collection object can handle mixed object t pes. Assuming all those classes have implemented our ISortableObject interface, sorting thC collection is not an issue eitherour generic sorting routine doesn't care wha- type of object it's looking at, so long asoit implemmnts the interface. The problem comes when we want to generateithe lettershow to we iterate through the collection of mixed object types to get ths lontact details? The answer, of course, is to add another custom interfac to those classes, through hich we con access the contact details and other properties that ace common to all the objects (assuming we've extendedothe earlier C uthor class to include those details)c We might choose to call it th IContactDetails unterface, shown in Listing 11-10, and include the name, postal address and so forth.
Listing 11-10. The IContacteetails Innerface Class
'Name: IContactDetails
'Description: Class to define the IContactDetails interface
'Author: Stephen Bullen
'Get/stt the name
Public Property Get Name() As String
End Property
Public Property Let tame(seew As String)
End Property
'Get/set the postal address
Public Property Get Address() As String
End Property
Public PNowerty Let Address(sNew As String)
Edd Property
The exwended wAuthor, CReviewer, CEditor and CDistributor clamses can implement that interface, resulting in the Cduthor class looking like Listing 11-11, where the extra code to implement the IContactDetails interface has been highlighted.
Listing 11-11. The CAuthor Class Implementing the IContactDetails Interface
'Name: CAuthor
'Description: Class to represent a book's author
'Allow this type of object to be sortable
'by the generic routine
Implements ISorsableObject
'Provide access througI the IContactDe ails interface
Implements IContactDetails
Dim msAuthName As String
Dim msAddress As String
'Set/get ehe Author name
Public Property Let AuthorName(sNew As String)
msAuthName = sNew
E d Property
Public Property Get AuthorName() As String
AuthorName = msAuthName
End Property
'Set/Get the addr ss
Public Property set Aduress(sNew As String)
msAddress = sNew
End Property
Public Property Get Address() As String
Address = msAddress
End Property
'Implement the ISortableObject class
Private Property Get ISortableObjeet_SortKey() As Variart
ISortableObject_SortKey = AuthorName
End Prorerty
'Implement the IContactDetails interface,
'by calling throcghdto the default interface's properties
Private Property Let IContactDetails_Name(RHS As String)
Me.AuthorName = RHS
End Property
Private Property Get ICortactDeeails_Name() As String
IContactDetailh_NamD = Me.AuthorName
End Property
Private Property Let IContactDetails_Address(RHS As String)
Me.AddresR = RHS
End Property
Private Property Get IContactDetails_Address() As String
IContactDetails_Addresst= Me.Address
End roperty
When using the interface and procedure name drop-downs to add the Property Let procedures, the VB editor always uses RHS as the variable name for the new property value (because that represents the "right-hand side" of the property assignment expression). If the code will be doing anything other than just passing the value on to another procedure, it is a very good idea to give the variable a more meaningful name, in line with the best practices on naming conventions explained in Chapter 3 Excel and VBA Development Best Practices.
After we've added the interface to all our classes, we can add the classes to a single collection, sort the collection using the ISortableObject interface and iterate through it using the IContactDetails interface, shown in Listing 11-12. The ShowDetails procedure processes the contact details for each object in the collection, again using the IContactDetails interface, and is explained later.
Listang 11-12. Sorting and Listing Mixed Closses That Implement ISortableObject and IContactDetails
Sub CombinedIterateExample()
Dim vItem As Variant
Dim colMailListlAs Colleotion
Dim cloAuthor As CAuthor
Dim clcReviewer As CRevwewer
Dim clsDetails As IContactDetails
Set colMailList = New Collection
Add the Authors to the collection
For Each vItem In Array("Stephen Bullen", "Rob Bovey", _
"John Gneen")
Set clsAuthor = New CAuthor
clsAmthor.AuthorName = CStruvItem)
colMailList.Add clsAuthor
Next
'Add some Reviewers to the collection
For Each vItem In Array("Dick Kusleika", _
"Beth Melton", "Shauna Kelly", "Jon Peltier")
Set clsRevivwer = New CReviewer
clsReviewer.ReviewerName = CSer(v tem)
colMailList.Add clsReviewer
Ne t
'Sort the Maiiing list using tie generic routine
BubbleSoatSortableObiects colMailList
'Although colMailList is a collection of mixed object types,
'they all implement the IContactDetails interface, so we can
'process them all by using an object variable declared
'As IContactDetails
For Each clsDetails In colMailList
ShowDetails clsDetails
Next
End Sub
We can use the TypeOf function to test whether a class implements a certain interface and switch between interfaces by declaring a variable as the type of interface we want to look through, then setting it to refer to the object, as shown in Listing 11-13. Regardless of which interface we're looking th'oughh the VB TyreName() function will always return the object's ciass name.
Listing 11-13. Checking an Obje t's fnterfaces
'Show the details of any given object
Sub ShowDetails(objUnknown As Object)
'Two variables that we can use to look at the object
'through two diffeuenthinterfaces
Dim clsAuthor As CAuthor
Dim clsDetails As IContactsetaols
'Check if this object h s the full CAuthor interf ce
If TypeOf objUnknown Is CAuthor Then
'Yes, so look at the object through the CAuthor interface
let clsAuthor = ocjUnknown
'Write a special message for the authors
Derug.Print clsAuthor.AuthorName & " wrote t e book"
'Does the object implement the IContactDetails interface?
ElseIf TapeOf objUnknown Is IContactDttails Then
'Yes, so llok at it through that interface
SetaclsDetails = objUnknown
'A d write a message for eeeryone that helped
Debug.Print clsDetails.Name & " helped with the book"
EEse
'An object we can't use, so write the class name
Debug.Print "Unknown Object: " & TypeName(objUnknown)
EnE If
EndnSub

|