Die Implementierung von Schnittstellen ist an sich eine
vielseitige und mitunter ungeahnte Möglichkeiten für die
Architektur einer Anwendung eröffnende Technik. Wenn sie denn nur
nicht manchmal etwas umständlich zu handhaben wäre...
So besteht das übliche Verfahren des Zugriffs auf eine
implementierte Schnittstelle darin, eine zusätzliche
Objekt-Variable des Typs der gewünschten Schnittstelle eines
Objekts anzulegen. Dann wird dieser Variablen die vorhandene
Referenz auf eine andere Schnittstelle zugewiesen. Und über diese
zusätzliche Objekt-Variable kann schließlich auf das gleiche
Objekt, nun über die andere Schnittstelle, zugegriffen werden:
Dim ObjInstanz As IrgendeinObjekt
Set ObjInstanz = New IrgendeinObjekt
' ...
Dim XYZ As AndereSchnittstelle
Set XYZ = ObjInstanz
XYZ.Irgendwas
Bei dieser umständlichen Zugriffsweise kann es leicht zu Pannen
kommen. Wenn Sie etwa die eine Objekt-Variable auf Nothing setzen,
in der Absicht, das Objekt freizugeben und terminieren zu lassen,
dabei jedoch übersehen, auch die zweite Variable auf Nothing zu
setzen, haben Sie mit Zitronen gehandelt - das Objekt terminiert
nur, wenn beide (!) Objekt-Variablen auf Nothing gesetzt worden
sind. Oder Sie verwenden womöglich die zusätzliche Objekt-Variable
für die Schnittstelle nacheinander mit mehreren verschiedenen
Objekt-Instanzen, unter Umständen sogar mit Instanzen von Objekten
unterschiedlichen Ausgangstyps, die lediglich jene eine
Schnittstelle gemein haben. Dann kann es nur allzu leicht vorkommen,
dass Ihnen die Übersicht abhanden kommt, auf welches konkrete
Objekt oder welche konkrete Objekt-Instanz welche Variable nun
verweist. Ganz problematisch und mit einer Erhöhung der
Wahrscheinlichkeit der Unentwirrbarkeit wäre eine nicht-lokale
Deklaration solcher Schnittstellen-Hilfs-Variablen auf Modul-Ebene
oder gar globaler Ebene in einem Standard-Modul - davon sollten Sie
zumindest in jedem Fall Abstand nehmen, auch wenn Ihnen der Umgang
mit den Hilfs-Variablen locker von der Hand gehen sollte.
Eine viel elegantere Lösung als Hilfs-Variablen bieten dagegen
explizite Schnittstellen-Umwandlungen über Objekt-Typ-spezifische
Funktionen. Ganz im Stil der Visual Basic-eigenen
Konvertierungsfunktionen können Sie nämlich auch Funktionen zur
Umsetzung von Schnittstellen anlegen. Bleiben wir einmal bei den
Objekt- und Schnittstellen-Typen des obenstehenden Beispiels und
legen wir folgende Hilfs-Funktion (etwa öffentlich in einem
Standard-Modul) an:
Public Function CAndereSchnittstelle(Obj As AndereSchnittstelle) _
As AndereSchnittstelle
Set CAndereSchnittstelle = Obj
End Function
Wichtig ist bei der Deklaration der Funktion, dass ihr
Rückgabewert dem Typ der gewünschten Schnittstelle entspricht. Der
Typ des Übergabeparameters ist im Prinzip ohne Bedeutung. Die Wahl
des gleichen Typs sorgt lediglich dafür, dass jedes beliebige
Objekt übergeben werden kann, das über die Schnittstelle verfügt,
unabhängig von seinem eigentlichen Basis-Typ.
Der Zugriff auf die Schnittstelle gestaltet sich nun wesentlich
schlichter - reduziert auf eine einzige Zeile:
CAndereSchnittstelle(ObjInstanz).Irgendwas
Sowohl für die Schnittstellenumwandlung über eine
Hilfs-Variable als auch wie hier über eine Hilfs-Funktion wird die
Möglichkeit der frühen Bindung vorausgesetzt - ein Verweis im
Projekt auf die Schnittstellen-Bibliothek muss in das Projekt
aufgenommen worden sein bzw. die Schnittstelle muss im gleichen
Projekt definiert sein. Ein Unterschied in der Performance ist daher
nicht auszumachen - nur wenn Sie die für das jeweilige Verfahren
benötigten Prozessortakte exakt mitzählen, werden Sie sicher
leichte Unterschiede anmerken können.
Einen kleinen Nachteil hat dieses Umwandlungsverfahren
allerdings. Wenn Sie mehrmals nacheinander auf die betreffende
Schnittstelle zugreifen wollen, werden Sie die Umwandlung entweder
bei jedem Zugriff vornehmen oder ein With...End With-Konstrukt
einsetzen müssen, also entweder:
CAndereSchnittstelle(ObjInstanz).Irgendwas
CAndereSchnittstelle(ObjInstanz).Nochwas
oder:
With CAndereSchnittstelle(ObjInstanz)
.Irgendwas
.Nochwas
End With
Eine ganz andere Möglichkeit ist, ein Objekt gleich von
vornherein mit Eigenschaften zu versehen, die einen Verweis auf die
Objekt-Instanz selbst, aber über eine andere Schnittstelle
zurückgeben:
Public Property Get ASchnittstelle() As AndereSchnittstelle
Set ASchnittstelle = Me
End Property
Der Zugriff auf diese Schnittstelle sähe dann folgendermaßen
aus:
ObjInstanz.ASchnittstelle.Irgendwas
oder:
With ObjInstanz.ASchnittstelle
.Irgendwas
.Nochwas
End With
Bei wiederum gleichen Performance-Kosten hätte diese Technik
allerdings den Nachteil, dass Sie sie nur von einem Basis-Objekt
ausgehend verwenden können, da Sie von diesem Objekt wissen, welche
Schnittstellen Sie dort implementiert haben. Bei der Definition
einer Schnittstelle können Sie jedoch nicht wissen, in welchem
Basis-Objekt die Schnittstelle jemals implementiert werden wird.
Unter Preisgabe der frühen Bindung und Inkaufnahme einer späten
Bindung samt Performance-Verlusten können Sie jedoch auch bei einer
Schnittstelle einen ähnlichen Weg gehen, indem Sie die
Schnittstelle mit einer simplen, allgemeinen Object-Schnittstelle
versehen (etwa entsprechend der Object-Eigenschaft der
Control-Schnittstelle eines jeden Steuerelements in Visual Basic).
In der Klasse des Objekts würde diese Schnittstellen-Eigenschaft
etwa so aussehen:
Private Property Get Object() As Object
Set Object = Me
End Property
Der umgekehrte Zugriff von einer auf die Schnittstelle
verweisenden Objekt-Variablen aus würde dann lauten, wenn das
Basis-Objekt beispielsweise selbst eine Methode namens MeineMethode
hätte:
Dim XYZ As AndereSchnittstelle
Set XYZ = New IrgendeinObjekt
' ...
XYZ.Object.MeineMethode
Alles in allem möchte ich jedoch festhalten, dass die Technik
der Umwandlungsfunktionen die beim Codieren bequemste, in Sachen
Performance kostengünstigste und insgesamt übersichtlichste und am
leichtesten wartbare Technik darstellt.
Zu guter Letzt bleibt noch die Anregung übrig, die
Umwandlungsfunktionen für Ihre Schnittstellen als Methoden einer
globalen Klasse (Instancing = GlobalMultiUse) in einer eigenen
ActiveX-DLL anzulegen. Dann brauchen Sie nur noch einen Verweis auf
diese DLL in das Projekt aufzunehmen, in dem die Schnittstellen
verwendet werden, und können dort die Funktionen direkt wie Visual
Basic-eigene Funktionen verwenden.
Die Beispiel-Projektgruppe, die Sie zu diesem Artikel
herunterladen können, zeigt Ihnen die beschriebenen Techniken und
Möglichkeiten noch einmal im Zusammenhang.
|