Objektorientiertes Programmieren mit Klassen

André Minhorst, Duisburg

VBA wird im Allgemeinen die Eigenschaft abgesprochen, eine objektorientierte Programmiersprache zu sein. Um diese Aussage zu untersuchen, müsste man erst einmal festlegen, ab wann eine Sprache objektorientiert ist und welche Eigenschaften für diese Bezeichnung vorhanden sein müssen. Lässt man einmal außen vor, dass Vererbung und Polymorphismus im VBA-Sprachgebrauch Fremdwörter sind, kann man VBA sicher als objektorientierte Sprache auffassen. Wie auch immer – im vorliegenden Beitrag erfahren Sie, wie Sie sich die objektorientierten Eigenschaften von VBA zu Nutze machen.

Wer mit Access arbeitet und dabei VBA für die Entwicklung von Datenbankanwendungen verwendet, kann vermutlich mit Objekten verschiedenen Typs umgehen – wenn er auch vielleicht noch nie einen eigenen Objekttyp erstellt hat.

Sicher hat jeder schon einmal ein Recordset via VBA geöffnet und auf die darin enthaltenen Methoden wie Open, MoveNext, AddNew, Update oder Close zugegriffen oder Informationen aus Eigenschaften wie RecordCount, EOF oder Filter verwendet. Beispiele dafür zeigt die Routine aus Quellcode 1, die eine auf der Tabelle tblKontakte basierende Datensatzgruppe öffnet und den Inhalt der einzelnen Datensätze ausgibt. Mit diesem Code erzeugt man unter anderem eine Instanz des Objekttyps Recordset, legt einige seiner Eigenschaften wie beispielsweise die Datenherkunft und die zugrunde liegende Verbindung fest und greift anschließend auf die so verfügbar gemachten Daten zu.

Public Sub OpenRecordset()
    Dim cnn As ADODB.Connection
    Dim rst As ADODB.Recordset
    Set cnn = CurrentProject.Connection
    Set rst = New ADODB.Recordset
    rst.Open "tblKontakte", cnn, adOpenKeyset, _        adLockPessimistic
    Do While Not rst.EOF
        Debug.Print rst!KontaktID, rst!Vorname, _            rst!Nachname
        rst.MoveNext
    Loop
    rst.Close
    Set rst = Nothing
    Set cnn = Nothing
End Sub

Quellcode 1

Eine weitere, ganz offensichtliche Objektart ist beispielsweise ein Formular – wie für ein Objekt üblich, verfügt es über Methoden, Eigenschaften und Ereignisse. Ein Formularobjekt kann wiederum Steuerelemente enthalten, die ebenfalls Objekttypen repräsentieren.

Mit den in Access vorhandenen Objekttypen lässt sich jede Menge nützlicher Dinge anstellen. Ein wichtiger Aspekt dabei ist, dass die unterschiedlichen Objekttypen bestimmte Methoden, Eigenschaften und Ereignisse enthalten. Ein Objekt des Typs Recordset fasst beispielsweise eine Menge Funktionalität zusammen. Und das Beste daran ist, dass man sich gar nicht darum kümmern muss, was im Innern dieses Objekts passiert – es reicht völlig aus, dass man die Methoden, Eigenschaften und Ereignisse kennt. Wen interessiert denn schon, was intern alles abläuft, wenn man die Methode AddNew eines Recordset-Objekts aufruft Wichtig ist allein das Kennen der Schnittstelle und dass das Objekt die gewünschten Reaktionen und Ergebnisse auf die getätigten Eingaben liefert.

Hinweis

Um keine Verwirrung bezüglich der hier verwendeten Begriffe aufkommen zu lassen, sollen folgende Definitionen gelten: Der Inhalt eines Klassenmoduls definiert eine Klasse. Eine Klasse wird auch Objekttyp genannt. Das Instanzieren einer Klasse beziehungsweise eines Objekttyps erzeugt ein Objekt. Auf das Objekt kann man in der Folge über die Objektvariable zugreifen. Das Klassenmodul enthält also einen Entwurf dessen, wie das Objekt sich verhalten soll. Dieser Entwurf besteht aus der Definition geeigneter Eigenschaften, Methoden und Ereignisse sowie der dahinter liegenden Funktionen.

Nun bietet Access nur eine begrenzte Menge Objekttypen, die allerdings bereits viele Anforderungen abdecken. Genau genommen sind Art und Menge der Objekttypen gerade so bemessen, dass sie als vernünftige Grundlage für den Aufbau der jeweils individuell abzubildenden Geschäftsprozesse einer Anwendung dienen.

Damit gibt es bereits einige gute Gründe, um eigene Objekttypen zu schaffen:

  • Objekttypen enthalten Methoden, Eigenschaften und Ereignisse und machen diese über eine leicht zugängliche Schnittstelle verfügbar.
  • Affinität: Mit der Definition eines Objekttyps macht man Softwareentwicklung wesentlich greifbarer, denn reelle Objekte wie beispielsweise der nachfolgend vorgestellte Kontakt können über realitätsnahe Attribute angesprochen werden.
  • Komplexität verbergen: Objekttypen verbergen mitunter komplexe Vorgänge, um die man sich, wenn sie einmal gestestet und praxiserprobt sind, keine Gedanken mehr machen muss. Der ansonsten offen liegende Code verschwindet in einer Black Box; nicht mehr die darin enthaltenen Techniken interessieren, sondern allein die Schnittstelle.
  • Wiederverwendbarkeit: Auf den Funktionsumfang eines Objekts kann man von der ganzen Anwendung aus zugreifen; unter Umständen können Objekttypen sogar in weiteren Anwendungen zum Einsatz kommen – beispielsweise, wenn die Klassen nicht an eine bestimmte Datenherkunft gebunden sind.
  • Weitergabe: Objekttypen können in Form von Klassenmodulen leicht weitergegeben werden; eine funktionierende Schnittstelle und eine brauchbare Dokumentation vorausgesetzt, können andere Entwickler diese leicht weiterverwenden.
  • Wie bereits oben erwähnt, ist einer der Vorteile der Verwendung von Objekttypen, dass man reelle Objekte und deren Eigenschaften in einer Einheit zusammenfassen kann, deren Methoden, Eigenschaften und Ereignisse über eine entsprechende Schnittstelle erreichbar sind. Unter VBA spricht man in diesem Zusammenhang von einem Klassenmodul.

    Als Beispiel für die Erläuterung des Aufbaus und der Verwendung von Objekttypen dient ein Kontakt. Er enthält bestimmte Informationen zu einer Person wie Vorname, Nachname, Geschlecht und Adressdaten. Um nicht nur die Verwendung von Eigenschaften, sondern auch den Einsatz von Methoden vorzustellen, erhält die Beispielobjektklasse zusätzlich eine Routine zur Ausgabe der Adressdaten in Form einer Anschrift.

    Hinweis

    Die zu den nachfolgenden Beispielen gehörenden Objekte und Codes finden Sie in der Beispieldatenbank OOMitAccess.mdb für Access 2000 und höher auf der beiliegenden CD.

    Erstellen eines Klassenmoduls

    Access stellt drei unterschiedliche Modularten zur Verfügung: die Klassenmodule von Formularen und Berichten, Standardmodule sowie Klassenmodule, die nicht an ein bestimmtes Objekt wie ein Formular oder einen Bericht gebunden sind. Die Klassenmodule von Formularen und Berichten sind prinzipiell mit den im Anschluss vorgestellten Klassenmodulen identisch; der einzige Unterschied ist, dass Letztere keine Oberfläche in Form eines Formulars oder Berichts enthalten.

    Um ein solches Klassenmodul zu erstellen, wählen Sie im VBA-Editor von Access den Menüeintrag Einfügen/Klassenmodul aus. Daraufhin öffnet Access ein fast leeres neues Klassenmodul, das Sie am besten direkt unter dem gewünschten Namen speichern – beispielsweise clsKontakt. Wählen Sie den Namen eines Klassenmoduls immer so, dass er auch verrät, welches Objekt sich dahinter verbirgt – später werden Sie über diesen Namen auf diese Klasse zugreifen.

    Praxis-Tipp

    Damit der Debugger sich meldet, wenn eine Variable nicht ordnungsgemäß deklariert ist, sollten Sie im Prozedurkopf die Anweisung Option Explicit hinzufügen.

    Schreib- und lesbare Variablen

    Die Eigenschaften eines Objekttyps speichert man in herkömmlicher Weise in Variablen. Die Zugriffsmöglichkeiten auf diese Variablen kann man allerdings wesentlich flexibler gestalten als in Prozeduren in Standardmodulen.

    Sie können eine Variable innerhalb eines Klassenmoduls natürlich als öffentlich zugänglich deklarieren, indem Sie etwa folgende Anweisung verwenden:

    Public Vorname As String

    Damit können Sie den Wert dieser Variablen von außen lesen und auch ändern, haben aber keinerlei Vorteile der in Klassenmodulen üblichen Art der Deklaration.

    Dort gibt es nämlich so genannte Property-Funktionen, über die man von außen den Wert einer Variablen lesen und ändern kann. Daher deklariert man Variablen in Klassenmodulen niemals als öffentlich, sondern immer als privat. Die Property-Funktionen erlauben nicht nur den schreibenden und lesenden Zugriff auf die privaten Variablen (wobei es für jede Zugriffsart eine eigene Funktion gibt), sondern man kann dort beliebige weitere Anweisungen unterbringen. Auf diese Weise lässt sich beispielsweise ein Zeiger setzen, der Informationen darüber enthält, ob sich eine Variable seit Erstellung der Objektinstanz geändert hat.

    Namenskonventionen

    Die Variablen, die über Property-Funktionen für die Außenwelt erreichbar sein sollen, kennzeichnet man durch Voranstellen eines weiteren Buchstabens zum eigentlichen Variablennamen. Genau genommen wählt man einen Namen aus, unter dem die Variable nach außen erscheinen soll, wie beispielsweise Vorname, und nennt die Variable intern mVorname.

    Hinzufügen einer Variablen

    Um eine bessere Vorstellung davon zu bekommen, was es mit diesen Property-Funktionen auf sich hat, fügen Sie der Klasse einfach eine Variable hinzu und erstellen zwei passende Property-Funktionen:

    Dim mVorname As String
    Public Property Get Vorname() As String
        Vorname = mVorname
    End Property
    Public Property Let Vorname(strVorname _    As String)
        mVorname = strVorname
    End Property

    Testen der Variablen

    Zum Testen der Funktionsweise verwenden Sie eine Prozedur namens BeispielKontakt in einem beliebigen Standardmodul. Um die Klasse verfügbar zu machen, deklarieren Sie zunächst eine entsprechende Objektvariable:

    Public Sub KontaktBeispiel()
        Dim objKontakt As clsKontakt
        ''... weitere Anweisungen
    End Sub

    Nach der Eingabe des Schlüsselwortes As erscheint die Liste aller verfügbaren Objekttypen, unter denen sich nun auch die neu erstellte Klasse befindet – wenn Sie also später mal eine ganze Menge eigener Objekttypen verwenden, müssen Sie sich noch nicht einmal mehr deren Namen genau merken.

    Anschließend erzeugen Sie eine Instanz dieses Objekttyps, die Sie in der Prozedur verwenden möchten:

    Set objKontakt = New clsKontakt

    Sie könnten die ersten beiden Anweisungen auch zu einer einzigen Anweisung zusammenfassen:

    Dim objKontakt As New clsKontakt

    Dadurch sparen Sie zwar eine Zeile, aber wenn Sie die Objektinstanz möglicherweise erst später benötigen oder es sich erst im Verlaufe der Prozedur herausstellt, ob Sie diese überhaupt brauchen, verschwenden Sie unter Umständen wertvolle Ressourcen.

    Damit auch alles seine Ordnung hat und Objekte nicht unnötig Speicherplatz belegen, obwohl sie nicht mehr benötigt werden, legen Sie vorsichtshalber jetzt schon die Anweisung zum Zerstören des Objektes an:

    Set objKontakt = Nothing

    Das ist zwar im vorliegenden Fall nicht unbedingt erforderlich, da das Objekt ohnehin nach Beenden der Prozedur zerstört wird, aber es ist programmiertechnisch sauberer. Die folgenden Beispielanweisungen fügen Sie natürlich vor dieser Anweisung ein, da sie sich sonst auf ein nicht mehr vorhandenes Objekt bezögen.

    Möchten Sie weiterlesen? Dann lösen Sie Ihr Ticket!
    Hier geht es zur Bestellung des Jahresabonnements des Magazins Access im Unternehmen:
    Zur Bestellung ...
    Danach greifen Sie sofort auf alle rund 1.000 Artikel unseres Angebots zu - auch auf diesen hier!
    Oder haben Sie bereits Zugangsdaten? Dann loggen Sie sich gleich hier ein:

    Schreibe einen Kommentar