Lies diesen Artikel und viele weitere mit einem kostenlosen, einwöchigen Testzugang.
Access-Entwickler sind nicht gerade verwöhnt, wenn es um objektorientierte Techniken unter VBA geht. Es gibt zwar die Möglichkeit, Klassen zu programmieren und Objekte auf Basis dieser Klassen zu erzeugen, aber Features wie Vererbung fallen weitgehend flach. Weitgehend Nun, zumindest die sogenannte Schnittstellenvererbung ist unter VBA möglich. Damit können Sie immerhin mehrere Ausprägungen einer Klasse nach den Vorgaben einer Schnittstelle implementieren und diese je nach Bedarf austauschen.
Bevor wir uns den technischen Feinheiten widmen, schauen wir uns erstmal den Sinn und Zweck der Schnittstellenvererbung an. Es gibt Anforderungen, die sehr ähnliche Vorgänge mit verschiedenen Techniken umsetzen. Ein Beispiel dafür ist das Versenden von E-Mails: Sie können dazu Outlook fernsteuern oder alternativ eine der vielen Klassen zum direkten Versenden von E-Mails via Winsock und SMTP einsetzen. Für Ihre Anwendung ist das Ziel immer gleich: Die E-Mail soll beim Empfänger ankommen und dafür stellen wir ein Paket aus Informationen wie Empfänger, Absender, Betreff und Inhalt der E-Mail zusammen. Der Rest interessiert uns nicht – dies sollen entsprechende Prozeduren erledigen.
Ein ähnliches Beispiel ist die Ausgabe von Daten. Diese sollen einmal in einem Bericht landen, ein anderes Mal in einem Word-Dokument, vielleicht aber auch einfach in einer Textdatei, in einem HTML- oder XML-Dokument oder als schlichte Ausgabe im Direktfenster des VBA-Editors.
Auch hier haben wir wenig Lust, uns darum zu kümmern, wie der Inhalt im entsprechenden Ausgabeformat landet – wir möchten höchstens festlegen, welches Ausgabeformat verwendet wird und gegebenenfalls die dorthin geschickten Daten filtern oder sortieren.
Dies alles ist mit herkömmlichen Prozeduren möglich. Im Falle der E-Mails würden Sie die Daten wie Absender, Empfänger, Betreff und Text etwa per Formular abfragen und dann die Prozedur zum Versenden der E-Mail aufrufen.
Diese entscheidet dann auf Basis vorher festgelegter Kriterien, ob die E-Mail mit Outlook oder direkt per SMTP verschickt wird, und steuert den entsprechenden Zweig einer If…Then– oder Select Case-Bedingung an. In den verschiedenen Zweigen steckt dann versandspezifischer Code oder schlicht ein Aufruf einer Funktion, welche den Versand auf die angegebene Weise durchführt.
Sie würden dann beispielsweise zwei Funktionen definieren, deren Prozedurköpfe etwa so aussehen:
Public Function MailToOutlook(strSender As String, strRecipient As String, strSubject As String, strBody As String) Public Function MailToSMTP(strSender As String, strRecipient As String, strSubject As String, strBody As String)
Die aufrufende Prozedur enthielte dann beispielsweise den folgenden Code:
Select Case strVersandart Case "Outlook" Call MailToOutlook (...) Case "SMTP" Call MailToSMTP (...) End Select
Sie haben hier alle Freiheiten: Die Funktionen MailToOutlook oder MailToSMTP könnten beispielsweise auch zusätzliche Parameter verwenden, oder Sie erweitern das Select Case-Statement um eine dritte Methode zum Versenden von E-Mails.
Klasse Funktion
Die Funktionen zum Versenden von E-Mails könnten auch in zwei Klassen ausgelagert werden. Die Klasse zum Versenden von E-Mails via SMTP könnte beispielsweise wie in Listing 1 aussehen. Die Klasse für den Versand mit Outlook sieht genauso aus, nur dass die Methode zum Versenden der E-Mail den Namen SendSMTPMail besitzt.
Listing 1: Klasse zum Versenden von E-Mails via SMTP
Private m_Sender As String Private m_Recipient As String Private m_Subject As String Private m_Body As String Public Property Let Sender(strSender As String) m_Sender = strSender End Property Public Property Let Recipient(strRecipient As String) m_Recipient = strRecipient End Property Public Property Let Subject(strSubject As String) m_Subject = strSubject End Property Public Property Let Body(strBody As String) m_Body = strBody End Property Public Function SendSMTPMail() As Boolean ''... Code zum Senden der Mail per SMTP SendSMTPMail = True End Function
Eine Prozedur, welche eine dieser beiden Klassen aufruft, sieht etwa wie in Listing 2 aus. Sie bekommt per Parameter den Versender, den Empfänger, den Betreff und den Inhalt sowie die Versandart übermittelt. Mit diesen Informationen entscheidet die Select Case-Bedingung, welcher der beiden Zweige angesteuert werden soll.
Listing 2: Instanzierung der Klassen zum Versenden von E-Mails und Versenden der E-Mail
Public Sub MailVersenden(strAbsender As String, strEmpfaenger As String, strBetreff As String, strInhalt As String, strVersandart As String) Dim objSendSMTPMail As clsSendSMTPMail Dim objSendOutlookMail As clsSendOutlookMail Select Case strVersandart Case "SMTP" Set objSendSMTPMail = New clsSendSMTPMail With objSendSMTPMail .Sender = strAbsender .Recipient = strEmpfaenger .Subject = strBetreff .Body = strInhalt If .SendSMTPMail = True Then MsgBox "Versand via SMTP erfolgreich!" End If End With Case "Outlook" Set objSendOutlookMail = New clsSendOutlookMail With objSendOutlookMail .Sender = strAbsender .Recipient = strEmpfaenger .Subject = strBetreff .Body = strInhalt If .SendOutlookMail = True Then MsgBox "Versand via Outlook erfolgreich!" End If End With End Select End Sub
Dadurch wird eine der beiden Klassen clsSendSMTPMail und clsSendOutlookMail instanziert. Danach füllt die Prozedur die Eigenschaften des auf diese Weise erzeugten Objekts und initiiert den Mailversand durch den Aufruf der Methode SendSMTPMail beziehungsweise SendOutlookMail.
Enge Kopplung
Die aufrufende Klasse ist dann allerdings sehr eng an die aufgerufenen Klassen gekoppelt. Wenn Sie die aufgerufenen Klassen so gestalten können, dass diese alle eine einheitliche Schnittstelle bieten – das heißt, dass jede Klasse die gleichen Methoden und Eigenschaften enthält -, können Sie eine abstrakte Schnittstelle für diese Klassen erstellen. Diese Schnittstelle fungiert dabei als eine Art „Vertrag“ – sie legt genau fest, wie die Implementierung der Klasse aussehen muss.
Klasse als Schnittstelle
Diese Schnittstelle ist eine eigene Klasse, die alle enthaltenen Methoden und Eigenschaften festlegt, aber keine Implementierungsdetails enthält.
Sie sagt also beispielsweise: Die Klasse, die meine Schnittstelle implementiert, muss vier öffentliche Property Let-Parameter namens strSender, strRecipient, strSubject und strBody mit dem Datentyp String und eine öffentliche Sub-Methode namens Send aufweisen – nicht mehr und nicht weniger.
Die Implementierung dieser Methoden und Eigenschaften folgt erst in den eigentlichen Klassen.
Die Implementierung enthält die eigentliche Funktionalität. Um sicherzustellen, dass die in der Schnittstelle vorgegebene Definition eingehalten wird, enthält diese Klasse die Anweisung Implements ISendMail. Die implementierten Methoden und Eigenschaften weisen eine spezielle Notation auf: Diese besteht aus dem Namen der zu implementierenden Schnittstelle, einem Unterstrich (_) und dem in der Schnittstellendefinition festgelegten Methoden- oder Eigenschaftsnamen.
Von der Klasse zur Schnittstelle
Wenn Sie bereits eine Klasse verwenden, welche die Eigenschaften und Methoden der geplanten Schnittstelle enthält, können Sie daraus ganz einfach die Schnittstelle erstellen: Werfen Sie einfach jede Codezeile mit Ausnahme von Option Explicit und gegebenenfalls Option Database sowie der eigentlichen Gerüste der öffentlichen Methoden und Eigenschaften raus. Wenn Sie die Klasse aus Listing 1 derart bearbeiten, bleibt der in Listing 3 dargestellte Rest. Diese Klasse speichern Sie unter dem Namen ISendMail. Das I steht für Interface, also Schnittstelle, und deutet darauf hin, dass diese Klasse nur die Schnittstellenbeschreibung und keinerlei Implementierung irgendwelcher Funktionen enthält.
Listing 3: Definition der Schnittstelle für die Klassen zum Versenden von E-Mails
Option Compare Database Option Explicit Public Property Let Sender(strSender As String) End Property Public Property Let Recipient(strRecipient As String) End Property Public Property Let Subject(strSubject As String) End Property Public Property Let Body(strBody As String) End Property Public Function SendMail() As Boolean End Function
Der einzige Unterschied in der Deklaration der Prozedurköpfe ist der, dass wir die Function-Prozedur SendSMTPMail in SendMail umbenannt haben. Der Grund ist klar: Die Schnittstelle soll später stellvertretend für beide vorhandenen oder sogar für noch weitere Klassen verwendet werden und deshalb neutrale, von der verwendeten Methode unabhängige Bezeichnungen aufweisen.
Anpassen der Implementierungen
Damit wir die beiden Klassen clsSendOutlookMail und clsSendSMTPMail später als Implementierung nutzen können, müssen wir diesen mitteilen, dass sie die Schnittstelle ISendMail implementieren.
Wenn Sie dies mit einer vorhandenen Klasse durchführen, brauchen Sie dieser zunächst nur die folgende Zeile im Kopf des Moduls hinzuzufügen:
Implements ISendMail
Um zu prüfen, ob die Klasse alle in der Schnittstelle vorgegebenen Elemente implementiert, brauchen Sie nur das Projekt zu kompilieren (VBA-Editor, Menüeintrag Debuggen|Kompilieren von <Projektname>). Das Ergebnis des ersten Anlaufs sehen Sie in Bild 1. Die Implementierung der Property-Prozedur Sender ist nicht in Ordnung. Die Lösung ist einfach: Alle Elemente der Implementierungen einer Schnittstelle müssen mit dem Namen der Schnittstellenklasse und einem Unterstrich beginnen, also beispielsweise ISendMail_Sender statt einfach nur Sender.
Ende des frei verfügbaren Teil. Wenn Du mehr lesen möchtest, hole Dir ...
Testzugang
eine Woche kostenlosen Zugriff auf diesen und mehr als 1.000 weitere Artikel
diesen und alle anderen Artikel mit dem Jahresabo