Praxiseinsatz von benutzerdefinierten Klassen in Microsoft Access

Die Seite wird erstellt Paul Gross
 
WEITER LESEN
Praxiseinsatz von
 benutzerdefinierten Klassen
    in Microsoft® Access
                                    Grundlagen – Beispiele – Tools
                                              Skriptum zum Vortrag auf der AEK7
                                                7. Access-Entwickler-Konferenz
                                                    Nürnberg, 25./26.9.2004

  Dieses Dokument entspricht im Wesentlichen dem Skriptum, wie es in der AEK-Teilnehmermappe zu finden
  war. Änderungen betreffen Tippfehler und verbesserungswürdige Formulierungen. Außerdem ist das
  Inhaltsverzeichnis ausführlicher und das Layout ein wenig luftiger gestaltet.

  Feedback jeder Art ist unter unten stehender E-Mail-Adresse ausdrücklich willkommen.

  Wien, am 27. September 2004
  Paul Rohorzka

© 2004 by Paul Rohorzka (paul.rohorzka@softconcept.at)                                   softconcept – rohorzka keg
                                                                                       Obere Amtshausgasse 6-8/13
Die Vervielfältigung, Veröffentlichung oder Weitergabe bedarf der                                      A-1050 Wien
schriftlichen Genehmigung des Autors.                                             +43 650 softcon (+43 650 7638266)
                                                                                                 www.softconcept.at
AEK 7 – Benutzerdefinierte Klassen im Praxiseinsatz

  Inhalt
           Wozu Klassen?......................................................................................................................................................................... 5

        Szenarien bei der Entwicklung mit Access ................................ ................................ ................................ .7
           Einleitung..................................................................................................................................................................................8
           Problembereich 1: Konsistente GUI ................................................................................................................................... 8
             Szenario ................................................................................................................................................................................8
             Schwierigkeiten.................................................................................................................................................................... 8
             Visionen................................................................................................................................................................................8
           Problembereich 2: Standard-Reaktionen auf Ereignisse .................................................................................................. 8
             Szenario ................................................................................................................................................................................8
             Schwierigkeiten.................................................................................................................................................................... 9
             Visionen................................................................................................................................................................................9
           Problembereich 3: Auswertung/Manipulation von Daten per Code ............................................................................ 9
             Szenario ................................................................................................................................................................................9
             Schwierigkeiten.................................................................................................................................................................... 9
             Visionen..............................................................................................................................................................................10
           Geht das? ................................................................................................................................................................................10

        Einführung in das Programmieren mit Klassen in VB(A) ................................ ................................ ........ 11
           Grundlagen .............................................................................................................................................................................12
             Prozedurale Programmierung.........................................................................................................................................12
             Objektorientierter/-basierter Ansatz.............................................................................................................................13
               Klassen...........................................................................................................................................................................13
           Elemente .................................................................................................................................................................................14
             Eigenschaften ....................................................................................................................................................................14
             Methoden ...........................................................................................................................................................................14
             Ereignisse ...........................................................................................................................................................................14
           Schnittstellen (Interfaces).....................................................................................................................................................14
           Objekte in VB(A) ..................................................................................................................................................................15
             Wert- vs. Referenztypen ..................................................................................................................................................15
                Werttypen ......................................................................................................................................................................15
                Referenztypen ...............................................................................................................................................................15
             Die Lebensdauer eines Objekts......................................................................................................................................16
                Erstellen eines Objekts................................................................................................................................................17
                Löschen von Objekten................................................................................................................................................17
                Zirkuläre Referenzen ...................................................................................................................................................17
             Syntax für den Zugriff auf Elemente ............................................................................................................................18
                Eigenschaften................................................................................................................................................................18
                Methoden.......................................................................................................................................................................19
                Ereignisse.......................................................................................................................................................................19
             Standard-Element .............................................................................................................................................................19
           Access-Objekte ......................................................................................................................................................................20
               Me ...................................................................................................................................................................................20
               cmdClose .......................................................................................................................................................................21
               DoCmd ..........................................................................................................................................................................21

        Entwickeln benutzerdefinierter Klassen in VB(A) ................................ ................................ .................... 23
           Allgemeines.............................................................................................................................................................................24

                                                                                                                                                                                                     2
AEK 7 – Benutzerdefinierte Klassen im Praxiseinsatz

           Elemente .................................................................................................................................................................................24
             Eigenschaften ....................................................................................................................................................................24
               Öffentliche Modulvariable..........................................................................................................................................24
               Eigenschafts-Prozedur ................................................................................................................................................25
               Unterschiede bei Wert- und Referenztypen ............................................................................................................26
               Parametrisierte Eigenschaften....................................................................................................................................27
             Methoden ...........................................................................................................................................................................27
             Ereignisse ...........................................................................................................................................................................28
               Rückmeldungen an das Objekt ..................................................................................................................................29
           Konstruktion und Destruktion ...........................................................................................................................................29
             Die Ereignisse Initialize und Terminate .......................................................................................................................29
           Schnittstellen (Interfaces).....................................................................................................................................................31
             Implementierung einer Eigenschaft ..............................................................................................................................31
             Implementierung einer Methode ...................................................................................................................................31
             Beispiel................................................................................................................................................................................32
           Auflistungs-Klassen ..............................................................................................................................................................33
                For Each-Unterstützung .............................................................................................................................................33
                Standard-Element ........................................................................................................................................................34
           Reaktion auf Ereignisse von Access-Objekten ................................................................................................................35
               Ereignis-Struktur bei Access-Oberflächen-Objekten ............................................................................................36

        Benutzerdefinierte Klassen im Praxiseinsatz ................................ ................................ ............................ 38
            Bemerkung zu Beginn......................................................................................................................................................39
           Helfer-Klassen (nicht Daten-gebunden) ...........................................................................................................................39
                CNamedValues.............................................................................................................................................................39
                CMoveAndSizeLabel ...................................................................................................................................................40
                CCoolButton.................................................................................................................................................................41
                CFormPosSize ..............................................................................................................................................................41
                CKeyDownForwarder.................................................................................................................................................42
                CDetailsHandler ...........................................................................................................................................................42
                CFormAppearance.......................................................................................................................................................42
           Datengebundene Klassen.....................................................................................................................................................43
             Helfer-Klassen mit Datenbankanbindung ...................................................................................................................43
               CFormHandling ...........................................................................................................................................................43
               CLogger .........................................................................................................................................................................43
               COptionGlobal, COptionLocal, COptionUser......................................................................................................43
             Datenkapsel-Klassen ........................................................................................................................................................44

        Tools zur Klassenentwicklung ................................ ................................ ................................ .................. 45
           Objektbrowser .......................................................................................................................................................................46
           VB6-Klassenassistent............................................................................................................................................................46
           Class Builder Wizard .............................................................................................................................................................46
           MZ-Tools................................................................................................................................................................................46
           softconcept sCodeTools.......................................................................................................................................................46

        Anhang ................................ ................................ ................................ ................................ ...................... 47
           Syntax-Auszeichnungen .......................................................................................................................................................48
           Paarweises Setzen und Löschen von Verweisen..............................................................................................................48
           Don’t: Dim ... As New …....................................................................................................................................................49

                                                                                                                                                                                                    3
AEK 7 – Benutzerdefinierte Klassen im Praxiseinsatz

           Aufzählungstypen..................................................................................................................................................................49
           Benennungs-Konventionen.................................................................................................................................................51
           Glossar.....................................................................................................................................................................................52
           Links ........................................................................................................................................................................................52
           Bücher .....................................................................................................................................................................................53

                                                                                                                                                                                                        4
AEK 7 – Benutzerdefinierte Klassen im Praxiseinsatz

  Wozu Klassen?

     Die Klasse, das unbekannte Wesen
        Bei aufmerksamer Beobachtung Access-relevanter Seiten im Internet (Community-Seiten, Firmen-Seiten und vor
        allem Newsgroups und andere Foren) fällt auf, dass Themen der objektorientierten Programmierung recht selten
        zur Sprache gebracht werden. Auf der einen Seite stehen zwar Entwickler1, die objektorientierte Konzepte
        zumindestens im Ansatz wie selbstverständlich in ihren Projekten verwenden, auf der anderen Seite findet sich
        aber die Vielzahl jener Entwickler, die Klassen höchstens im Rahmen eines Copy- und Paste-Vorgangs in die
        Finger bekommen2. Auf Fragen in Bezug auf derartige Problemstellungen antworten auch meistens nur eine
        Handvoll Leute.
        Was ist nun der Grund, dass gerade im Bereich der Access-Entwicklung objektorientierte Konzepte von vielen
        Entwicklern aktiv nicht angewandt werden? Vielleicht ist ein Grund darin zu suchen, dass aufgrund der
        ausgeprägten RAD- (Rapid Application Development) Features von Microsoft ® Access der theoretische
        Unterbau der Entwickler oft nicht in dem Maß ausgeprägt ist, wie bei Anwendern andere r Software-
        Entwicklungswerkzeuge. Schließlich kann man mit Access selbst mit rudimentären Programmierkenntnissen fürs
        erste annehmbare Anwendungen erstellen.
        Ein weiterer Punkt ist wohl auch die defacto fehlende Hilfestellung der Klassenprogrammierung seit ens Access.
        In der Sammlung der mit Access mitgelieferten Assistenten findet sich kein einziger zur Unterstützung der
        Klassenprogrammierung. Im VBE (Visual Basic Editor) beschränkt sich die Unterstützung auf das Einfügen von
        Eigenschafts-Prozeduren (Menü Einfügen - Prozedur). Durch AddIns von Drittanbietern, wie der beliebten
        Freeware MZ-Tools, dem Class Builder Wizard von Dev Ashish und Terry Kreft oder den Tools von FMS lassen
        sich zweifelsohne besser geeignete Werkzeuge finden. Deren Funktionsumfang befindet sich dennoch meilenweit
        hinter dem, was man heutzutage von einem OOD-Tool (Datamodelling und Coding-Tools) erwartet3.

     Vorteile der Verwendung von Klassen
        Ist gibt wohl keine Aufgabenstellung in der Anwendungs-Entwicklung unter Access, die sich nicht ohne der
        Verwendung einer einzigen Klasse realisieren ließe. Für viele Probleme existieren Lösungen, die oft auf
        Sammlungen von Funktionen und Prozeduren in einem oder mehreren Standard-Moduln basieren.
        Was sind aber nun die Vorteile, die der Entwickler aus der Entwicklung mit benutzerdefinierten Klassen ziehen
        kann? Ich möchte einige hier anführen:
             · Klassen können ohne weiteres Zutun des Entwicklers Standard-Verhalten bieten. Bei Funktionen
                  könnte dieser Zustand nur durch viele optionale Parameter erreicht werden. Das ist sowohl für den
                  Entwickler der Funktionen als auch für den Verwender der Funktionen mit einigem Aufwand
                  verbunden.
             · Die Verwendung von Klassen-Eigenschaften statt Funktionsparametern liefert automatisch besser
                  lesbaren Quellcode.

                   Beispiel einer prozeduralen Implementierung:
             Call NeuerArtikel("Seife", "Toiletteartikel", 0.79, 100, 30, 2)

        1 Der Begriff “Entwickler” soll in diesem Skriptum auch unausgesprochen die zum Glück vertretenen weiblichen
        Entwicklerinnen mit einschließen.
        2 “Nimm dazu doch die Klasse clsXxx von Xxx. Du kannst sie dir unter http://www.Xxx.Xxx/Xxx

        herunterladen!”
        3 Hier sei stellvertretend IBM Rational („Rational Rose“) genannt, auch wenn das im vorliegenden

        Zusammenhang beinahe schon ein hinterhältiger und unzulässiger Vergleich ist. Schließlich spielen solche Tools
        in einer völlig anderen Liga.

                                                                                                                        5
AEK 7 – Benutzerdefinierte Klassen im Praxiseinsatz                                     Szenarien bei der Entwicklung mit Access

                   Der selbe Vorgang unter Zuhilfenahme eines Objekts könnte so aussehen:
             With artNeu
                .Bezeichnung = "Seife"
                .Warengruppe = "Toiletteartikel"
                .Preis = 0.79
                .Lagerstand = 100
                .Mindestlagerstand = 30
                .Lager = 2
             End With

             ·     Bei Aufgabenstellungen, in den Zwischenergebnisse vorgehalten werden müssen, wird es eventuell sehr
                   mühsam, da ein Mechanismus bereitgestellt werden muss, der die jeweils richtige n Zwischenergebnisse
                   an die Funktionen übergeben werden. Anwendungen, die dies verdeutlicht, sind die Klasse
                   CMoveAndSizeLabel (siehe Seite 40) oder die Klasse CFormPosSize (siehe Seite 41).
             ·     Features, bei denen auf Ereignisse von Steuerelementen oder Formularen reagiert werden muss, lassen
                   sich nur mit Hilfe von Klassen sinnvoll realisieren. Andere Möglichkeiten, wie der direkte Aufruf von
                   Funktionen in den Ereignis-Eigenschaften sind in Hinblick auf Fehlersuche und Dokumentation für die
                   Anwendung im großen Stil kaum praktikabel.
             ·     Access ist von Haus aus ein objektbasiertes System, das dem Entwickler viele eingebaute Objekte zur
                   Verfügung stellt (Form, Report, TextBox, CommandButton, DoCmd, …). Entwickler sind
                   gewohnt, mit diesen Objekten zu arbeiten. Warum soll es dann nicht ebenso möglich sein, objektbasiert
                   auf die eigentlichen Nutzdaten der Anwendung zuzugreifen? Diese Möglichkeit besteht unter
                   Berücksichtigung der Einschränkungen durch VB(A) und Access.

     Über dieses Skriptum
        Ich habe für den vorliegenden Text einen bewusst pragmatischen Zugang gewählt. Es geht mir nicht um das
        vollständige Abdecken Objektorientierter Konzepte in allen Varianten und Ausprägungen. Vielmehr möchte ich
        die durchwegs positiven Erfahrungen aus meiner Arbeit als Entwickler unter Access in Bezug auf benutzer-
        definierte Klassen dem Leser näherbringen.
        Ich weiß, dass es mir nicht gelingen wird, alle Skeptiker des Themas (und davon soll es ja einige geben) zu
        überzeugen und möchte die Verwendung von Klassen auch nicht als Allheilmittel für alle Access-Probleme
        verkaufen. Ich möchte hingegen einen Beitrag leisten, die Arbeit manches Access-Entwicklers vielleicht ein wenig
        effizienter und vielleicht sogar einfacher zu gestalten.
        Der Vortrag auf der AEK7, dessen Skriptum Sie in Händen halten, soll somit ein kleiner Impuls sein, die
        deutschsprachige Community verstärkt auf die Vorteile der Entwicklung auf Basis objektorientierter Konzepte
        auch unter Access aufmerksam zu machen.

                                                                                                                              6
Szenarien bei der
Entwicklung mit Access
                Anforderungen
             Implementierungen
                     Probleme
                      Visionen
AEK 7 – Benutzerdefinierte Klassen im Praxiseinsatz                                  Szenarien bei der Entwicklung mit Access

  Einleitung
        In diesem Abschnitt möchte ich einige typische Szenarien bei der Entwicklung mit Microsoft ® Access anführen
        und die Probleme, Lösungsmöglichkeiten und Visionen in diesem Zusammenhang beleuchten.

  Problembereich 1: Konsistente GUI

     Szenario
        Der Großteil der Formulare in einer Anwendung hat viele Eigenschaften und Anforderungen gemeinsam:
            · Konsistentes GUI (Farben, Beschriftungen, Positionen, ...)
            · Durch den Endbenutzer in gewissem Rahmen konfigurierbares GUI
            · Wiederherstellen der Formulare in der zuletzt eingestellten Größe, an der letzten Position
            · Sinnvolle Ausnützung des Bildschirms durch größenänderbare Formulare (nicht die Anpassung an
               verschiedene Auflösungen mit Skalierung des gesamten Inhalts, sondern größere Arbeitsbereiche, z.B.
               Listen bei größerem Fenster, Verankern von Steuerelementen am rechten/unteren Rand)

     Schwierigkeiten
        All diese Features lassen sich implementieren, aber:
             · Der Code dazu muss in jedem Formular sehr ähnlich wiederholt werden (Copy, Paste & Modify)
             · Gewünschte Änderungen des Verhaltens müssen im Code jedes Formulars durchgeführt werden,
                  mit allen Fehlern, die dabei passieren, Inkonsistenzen, die sich damit einschleichen.
             · Neues Verhalten muss in jedem Formular nachgerüstet werden.

     Visionen
             ·     Implementieren des Codes an zentraler Stelle
             ·     Einfache Anwendung dieses Codes auf alle erforderlichen Formulare
             ·     Anpassungen und Erweiterungen an zentraler Stelle

  Problembereich 2: Standard-Reaktionen auf Ereignisse

     Szenario
        Die meisten Formulare einer Anwendung haben einige Features gemeinsam:
            · Standard-Schaltflächen (Ok, Abbrechen, Übernehmen, Neu)
            · Navigation (Auswahlliste, Such-Kombinationsfeld, History, Vor- Zurück, ...)
            · Behandlung fehlender oder fehlerhafter Eingaben
            · Anzeigen des zuletzt angezeigten Datensatzes

                                                                                                                           8
AEK 7 – Benutzerdefinierte Klassen im Praxiseinsatz                                     Szenarien bei der Entwicklung mit Access

     Schwierigkeiten
        Auch hier ist die Implementierung zweifellos möglich, jedoch mitunter sehr mühsam und vor allem
        fehlerträchtig. Einige Schwierigkeiten im vorliegenden Problembereich:
             · Anpassung an Bezeichnungen der zugrundeliegenden Tabelle (Tabellenname, Primärschlüsselfeld,
                  Felder mit Klartext zum Suchen, etc.)
             · Änderungen bei den erforderlichen Feldern erfordern beim Wunsch nach aussagekräftigen Meldungen
                  ziemliche Arbeit.

     Visionen
             ·     Erweitertes Standardverhalten von Formularen an zentraler Stelle wart- und änderbar
             ·     Anpassung an Änderungen in der Datenstruktur an möglichst wenig stellen im Code

  Problembereich 3: Auswertung/Manipulation von Daten per
  Code

     Szenario
        Zugriff auf die Daten der Datenbank. Einfachster Fall unter Verwendung einer fragwürdigen Domänen-
        Aggregatfunktion:
             strLastName = DLookup("Cust_LastName", _
                                   "tblCustomers", _
                                    "CustomerID = " & lngCustomerID)

        Alternative: Verwendung eines Recordsets (auch noch ohne Fehlerbehandlung!):
             Dim rstCustomers As DAO.Recordset

             Set rstCustomers = CurrentDb().OpenRecordset( _
                "SELECT * FROM tblCustomers WHERE CustomerID = " & _
                               lngCustomerID)

             If Not rstCustomers.EOF Then
                strLastName = Nz(rst.Fields("Cust_LastName").Value,"")
             End If

             If Not (rstCustomers Is Nothing) Then rstCustomers.Close
             Set rstCustomers = Nothing

     Schwierigkeiten
             ·     Wird oft und an verschiedensten Stellen in der Anwendung benötigt
             ·     Mühsam und fehleranfällig
             ·     Änderungen an der Datenstruktur haben oft schwer absehbare Konsequenzen für den Code in den
                   einzelnen Formularen.
             ·     Die Einhaltung von Geschäftsregeln muss jedesmal neu sichergestellt sein.
             ·     Änderungen in den Geschäftsregeln müssen an allen relevanten Stellen (wo sind alle?)
                   vorgenommen werden.

                                                                                                                              9
AEK 7 – Benutzerdefinierte Klassen im Praxiseinsatz                          Szenarien bei der Entwicklung mit Access

     Visionen
        Ideal wäre ein tatsächlich objektbasierter Zugriff auf die Daten:
             strLastName = Customers(lngCustomerID).LastName

        Vorteile:
            · Unabhängig von Bezeichnungen der Tabellen und Felder, sogar unabhängig von der tatsächlichen
                  Herkunft (in einem Feld einer Tabelle oder durch Berechnungen aus anderen Feldern)
            · Code ist weit unabhängiger von Details der Datenspeicherung (Struktur, Datenbank, ...)
            · Die Objekte können die Einhaltung von Geschäftsregeln erzwingen

        Ausführlicheres Beispiel:
             With Customers(lngCustomerID)
               MsgBox "Der Kunde " & .PrettyName & _
                      " hat die Rechnung Nr." & .Invoices(InvID).No & _
                      " bereits am " & .Invoices(InvID).Paid & _
                      " bezahlt." & vbNewLine & _
                      "Die " & .Invoices(InvID).Details.Count & _
                      " Posten wurden am " & _
                      .Invoices(InvID).Delivery.ShipDate & _
                      " geliefert."
             End With

  Geht das?
        Lassen sich diese Anforderungen in die Praxis umsetzen?
        Mit welchem Aufwand ist eine Umsetzung verbunden?
        Kann ich das nicht auch alles ohne Klassen erreichen?

                                                                                                                  10
Einführung in das
Programmieren mit
   Klassen in VB(A)
                Grundlagen
                   Elemente
               Schnittstellen
            Objekte in VB(A)
           Objekte in Access
AEK 7 – Benutzerdefinierte Klassen im Praxiseinsatz                           Einführung in das Programmieren mit Klassen in VB(A)

  Grundlagen
        Im Allgemeinen lässt sich die Funktion jeder Software auf folgende abstrakte Weise beschreiben: Zu
        verarbeitende Daten werden durch Steuerung (meist eines Benutzers) in Ergebnis-Daten transformiert.
        Beispielsweise wird aus den Daten einer Datenstruktur mit Kunden-, Artikel- und Bestelldaten eine Rechnung
        generiert. Aus der Sicht des Software-Entwicklers stellt sich diese Aufgabenstellung als Zusammenspiel einer
        Vielzahl von einzelnen Verarbeitungsschritten dar. Jeder dieser Schritte ist für die Erledigung eines im Idealfall
        klar abgegrenzten Teils des Gesamtproblems zuständig. Für diese Teil-Aufgabenstellung ist ein Teil der Daten
        notwendig, und das Ergebnis wird mittelbar oder unmittelbar zum Ergebnis des gesamten Prozesses beitragen.
        Die effektive Aufgabenteilung und Zusammenführung der Einzelergebnisse ist wiederum Teil der Aufgabe
        übergeordneter Prozeduren.
        Wie die konzeptionelle Umsetzung dieser Struktur aussehen kann, soll nun im Folgenden näher betrachtet
        werden.

     Prozedurale Programmierung
        Bei der klassischen Prozeduralen Programmierung, wie sie von Sprachen wie Pascal, C, Ba sic, etc. unterstützt
        wird, liegt es in der Verantwortung des Entwicklers, im Sinne obiger Überlegung die richtigen Funktionen mit
        den richtigen Daten zu beschicken sowie die Ergebnisse der Teil-Funktionen korrekt zusammenzuführen:
        Für die Entwicklung mit VB(A) bedeutet dies, dass der Entwickler zur Erfüllung einer Teilaufgabe die Variablen
        mit den zu verarbeitenden Daten in der vorgesehenen Art und Weise an die passende Funktion übergeben muss,
        und die von ihr erhaltenen Daten wieder entsprechend weiter verarbeiten muss.
        Dieser Vorgang ist wenig intuitiv. Die alltägliche Situation "Fahrrad fahren" würde nach prozeduraler
        Vorgangsweise als Anwenden der Aktion "Fahren" auf die Daten "Fahrrad" formuliert werden können (Pseudo -
        Syntax: Fahren(Fahrrad)). Eine unzulässige Zuordnung wäre aber die Aktion "Fahren" auf die Daten
        "Papierstoß" anzuwenden (Pseudo-Syntax: Fahren(Papierstoß)).

                            Daten 1

                                                           ?
                                                                                 Prozedur A

                                          Daten 2
                       Daten 3                                                                      Prozedur B

                                             Daten 4                          Prozedur C

                          Daten 5

                                          Daten 6                                          Prozedur D

        Fehler wie dieser, nämlich die Übergabe unpassender Daten an eine Funktion lassen sich im Allgemeinen nicht
        bereits zur Übersetzungszeit (vom Compiler) finden, sondern treten entweder erst zur Laufzeit auf oder zeigen
        sich lediglich in falschen Ergebnissen. Vom Compiler können nur jene Fehler gefunden werden, die inkompatible
        Datentypen beteiligt sind. Gerade in diesem Zusammenhang sind die Fähigkeiten der impliziten Typumwandlung
        des VB(A)-Compilers eher ein Problem als ein Segen.

        Da gerade in Datenbank-Anwendungen sehr oft mit Primärschlüsselwerten in Form von AutoWerten vom
        Datentyp Long gearbeitet wird, ist das Problem der unpassenden Daten besonders dramatisch. Nehmen wir an,
        es gibt eine Prozedur Bestellen, die als Parameter den zu bestellenden Artikel in Form der ArtikelID, die
        gewünschte Anzahl in Form eines Integer-Parameters und den Lieferanten in Form der LieferantenID
        erwartet.

        Diese wäre eine korrekte Verwendung dieser Prozedur:
             Call Bestellen(lngArtikelID, intStueck, lngLieferantenID)

        lngArtikelID, intStueck und lngLieferantenID seien Long- bzw. Integer-Variablen mit
        entsprechenden Werten.

                                                                                                                               12
AEK 7 – Benutzerdefinierte Klassen im Praxiseinsatz                                 Einführung in das Programmieren mit Klassen in VB(A)

        Es ist für den Compiler nun völlig korrekt, ruft der Entwickler diese Funktion mit völlig unpassenden Daten auf:
             Call Bestellen(lngKundenID, Day(Now()), lngDruckerID)                                   ' sinnlos!

        Diese semantisch absolut sinnlose Verwendung der Prozedur Bestellen zeigt erst zur Laufzeit Probleme.
        Diese Probleme zeigen sich bestenfalls in Form einer Verletzung der referenziellen Integrität, die in einen
        Laufzeitfehler mündet, schlimmstenfalls aber lediglich in fehlerhaften Daten.

     Objektorientierter/-basierter Ansatz
        Der objektorientierte Ansatz umgeht nun das Problem der Anwendung der korrekten Prozeduren auf die
        passenden Daten durch die Zusammenfassung der Daten mit den zugehörigen Funktionen. Eine solche
        Kombination von konkreten Daten mit den dazugehörenden Funktionen heißt Objekt:

                                                                         Objekt 2

                                                                              Prozedur B

                              Objekt 1                       Daten 2

                                                                              Prozedur C

                   Daten 1            Prozedur A

                   Daten 3            Prozedur B                                                  Daten 4           Objekt 3

                                                           Objekt 4
                                                                                                  Daten 5            Prozedur D

                                                                Prozedur B

                                                 Daten 7                                          Daten 6

                                                                Prozedur C

        Klassen
        Wie ein konkretes Objekt aufgebaut ist, also aus welchen Elementen (im Wesentlichen Daten und Prozeduren) es
        besteht und wie diese Elemente miteinander interagieren (also der Programmcode), wird durch seine Klasse
        bestimmt. Eine Klasse ist also sozusagen die Vorlage für die Erstellung eines konkreten Objekts. Man spricht
        auch davon, dass ein konkretes Objekt eine Instanz der zugrundeliegenden Klasse ist. Der Vorgang der
        Erstellung eines konkreten Objekts heißt daher auch instanziieren.
        Eine Klasse verhält sich zu den nach ihr instanziierten Objekten ähnlich einem Datentyp zu einer konkreten
        Variable dieses Datentyps.
        Diese Kombination aus Daten und Prozeduren kommt dem menschlichen besser Denken entgegen. Angewandt
        auf das obige Beispiel "Fahrrad fahren" würde das bedeuten, auf das Objekt "Fahrrad" sehr wohl die Aktion
        "Fahren" anwenden zu können (VB-Syntax: Fahrrad.Fahren), jedoch nicht auf das Objekt "Papierstoß", da
        dieses Objekt keine Aktion "Fahren" bietet (stattdessen vielleicht eine Aktion "Sortieren" – VB-Syntax:
        Papierstoß.Sortieren). Fehlerhafte Kombinationen können nun bereits vom Compiler erkannt werden, da
        im Gegensatz zu Fahrrad.Fahren der Ausdruck Papierstoß.Fahren nicht korrekt sein kann – die
        Klasse des Objekts Papierstoß bietet keine Methode namens Fahren.

                                                                                                                                     13
AEK 7 – Benutzerdefinierte Klassen im Praxiseinsatz                         Einführung in das Programmieren mit Klassen in VB(A)

        Mehrere Instanzen der selben Klasse
        In obiger Grafik sehen wir, dass von der selben Klasse selbstverständlich mehrere Instanzen existieren können.
        Objekt 2 und Objekt 4 stellen offenbar Instanzen der selben Klasse dar. Gemeinsam sind diesen beiden
        Objekten daher die Prozeduren (Prozedur B und Prozedur C). Unterschiedlich sind jedoch die Daten (Daten 2
        und Daten 7). Es ist zu beachten, dass bei der tatsächlichen Implementierung des Klassenkonzepts der Code der
        Prozeduren und Funktionen (die sogenannten "Methoden" – siehe unten) einer Klasse nur ein einziges Mal im
        Speicher existiert, gleich wieviele Instanzen dieser Klasse angelegt werden. Um die Methoden mit den korrekten
        Daten arbeiten zu lassen, wird jeder Methode einer Klasse beim Aufruf ein zusätzlicher versteckter Parameter
        übergeben, der einen Verweis auf die Daten der zugehörigen Instanz der Klasse enthält.

        Beim objektorientierten Ansatz wird die komplette in einem Objekt steckende Komplexität vor dem Anwender
        (i.e. dem Entwickler, der mit dieser Klasse programmiert) verborgen. Der Anwender muss sich also im
        Allgemeinen nicht darum kümmern, woher das Objekt seine Daten erhält, bzw. was es mit seinem Zustand tut.
        Es ist für den Anwender auch unerheblich, wie in der Klasse eine bestimmte Funktionalität implementiert ist
        ("Blackbox-Prinzip", Datenkapselung).

  Elemente
        Jede Klasse kann aus folgenden Elementen bestehen: Eigenschaften, Methoden, Ereignissen

     Eigenschaften
        Eigenschaften repräsentieren den Zustand (die Daten) eines Objekts.

        Beispiele:
            · Das Gewicht eines Fahrzeugs
            · Die Farbe eines Steuerelements

     Methoden
        Unter dem Begriff Methoden werden die Funktionen und Prozeduren des Objekts zusammengefasst.

        Beispiele:
            · Reparieren eines Fahrzeugs
            · Drucken eines Berichts

     Ereignisse
        Unter COM (Component Object Model) und damit VB(A) können Objekte andere Objekte vom Eintritt
        bestimmter Zustände informieren. Diese Information kann mittels Ereignissen übermittelt werden.

        Beispiele:
            · Das Licht des Fahrzeugs ist ausgefallen
            · Das Steuerelement hat den Fokus verloren

  Schnittstellen (Interfaces)
        Schnittstellen (Interfaces) beschreiben eine Schnittstelle einer Klasse nach außen. Über die Elemente der
        Schnittstelle können übergeordnete Programmteile mit dem Objekt in Kontakt treten.

        Eine Schnittstelle ist definiert durch eine Gruppe von
            · öffentlichen Eigenschaften
            · öffentlichen Methoden

                                                                                                                             14
AEK 7 – Benutzerdefinierte Klassen im Praxiseinsatz                           Einführung in das Programmieren mit Klassen in VB(A)

        Durch Schnittstellen können Objekte unterschiedlicher Klassen auf eine einheitliche Art und Weise
        angesprochen und verwendet werden, sofern sie die durch die Schnittstelle definierten Stan dards erfüllen. Man
        spricht hier davon, dass die Klasse eine Schnittstelle implementiert ("Schnittstellenvererbung").
        Eine Klasse kann mehrere Schnittstellen implementieren. Beispielsweise kann eine Klasse CPerson sowohl ein
        Interface IMitarbeiter als auch ein Interface IKunde implementieren. Somit kann ein Objekt der Klasse
        CPerson einmal als Mitarbeiter und einmal als Kunde betrachtet werden. Jede Klasse implementiert
        automatisch ein Standardinterface, das aus allen öffentlichen Eigenschaften und Methoden der Klasse besteht.

        Der große Vorteil der Schnittstellen wird offenbar, wenn versucht wird, Programmteile nicht für Objekte
        bestimmter Klassen, sondern für Schnittstellen zu schreiben. Verlangt beispielsweise ein Programmteil zur
        Lohnverrechnung von den zu bearbeitenden Objekten lediglich, dass sie Schnittstelle IMitarbeiter
        implementieren, ist es unerheblich, von welchen konkreten Klassen die übergebenen Objekte instanziiert
        wurden. Es könnten zum Beispiel sowohl die Klasse CAngestellter als auch die Klasse CArbeiter die
        Schnittstelle IMitarbeiter implementieren. Für den Programmteil zur Lohnverrechnung ist es nun
        gleichgültig, ob ein übergebenes Objekt eine Instanz der Klasse CAngestellter oder der Klasse
        CArbeiter ist. Der Programmteil betracht beide Objekttypen durch die Elemente der gemeinsamen
        Schnittstelle IMitarbeiter ("Polymorphismus").

        Durch das Entwickeln gegen Schnittstellen statt gegen konkrete Klassen kann folgender Nutzen gezogen
        werden:
            · Der Code funktioniert für viele unterschiedliche Implementierungen
            · Relevante Mengen von Code können über weite Strecken Copy&Paste-fähig gemacht werden.
                Klassen-Spezifika finden sich oft nur mehr im Deklarationsabschnitt, aber nicht im eigentlichen Code.

  Objekte in VB(A)

     Wert- vs. Referenztypen

        Werttypen
        Wird eine Variable eines eingebauten VB-Datentyps, Aufzählungstypen oder Benutzerdefinierten Datentyps
        (UDT) erstellt, so repräsentiert der Variablenbezeichner in allen weiteren Zugriffen den aktuellen Wert dieser
        Variablen:
             Dim curUmsatz As Currency
             Dim curGewinn As Currency
             Dim curKosten As Currency

             ' ...

             curUmsatz = 123.5   ' Der Wert der Variablen curUmsatz
                                 ' wird auf 123,50 gesetzt
             curGewinn = curUmsatz – curKosten ' curUmsatz steht für 123,50

        Solche Variablen werden daher auch als Werttypen bezeichnet. Zwei Variablen können nicht den selben
        Speicherplatz benennen.
        Zuweisungen an Variablen von Werttypen erfolgen im Allgemeinen durch Zuweisung mittels des Operators =:
             intAnzArbeitstage = intAnzGesamtTage - intAnzFreieTage

        Referenztypen
        Bietet eine Variable Zugriff auf eine Instanz einer Klasse (also auf ein Objekt), so sprechen wir von einer
        Objektvariablen. Sie stellt lediglich eine Referenz (einen Verweis) auf das eigentliche Objekt dar.
        Die Reservierung des Speicherplatzes für den Objektverweis erfolgt mittels Dim-Anweisung:

                                                                                                                               15
AEK 7 – Benutzerdefinierte Klassen im Praxiseinsatz                           Einführung in das Programmieren mit Klassen in VB(A)

             Dim objChef As CMitarbeiter

        Es sind natürlich auch die Varianten mit Public bzw. Private (auch Global und Friend) möglich.
        Eine Erweiterung dieser Syntax ist für Objekte, die Ereignisse auslösen können möglich. Siehe dazu Abschnitt
        "Ereignisse" auf Seite 19.
        Beachten Sie, dass diese Anweisung keinen Speicherplatz für das Objekt selbst reserviert. Dies kann zwar mit
        einer Erweiterung der Dim-Anweisung um das Schlüsselwort New erreicht werden, was aber gravierende
        Nachteile mit sich bringt. Näheres dazu siehe Anhang ("Don’t: Dim ... As New …" auf Seite 49).

        Zuweisungen an Objektvariablen erfolgen über die Set-Anweisung:
             Set objChef = Employees(lngChefEmpID)

        Mehrere Objektvariablen können auf das selbe Objekt verweisen:
             Set objMitarbeiterDesMonats = objJudith
             Set objChef = objJudith

        In obigem Beispiel halten beide Variablen eine Referenz auf ein und dasselbe Objekt, nicht auf getrennte Kopien
        zweier Instanzen.

        Explizites Beenden einer Referenzierung
        Referenzierungen werden durch Zuweisung des Schlüsselwortes Nothing aufgehoben:
             Set objChef = Nothing

        Wird die Objektvariable nicht explizit auf Nothing gesetzt, so wird der Verweis aufgehoben, wenn die
        Objektvariable ihren Gültigkeitsbereich verlässt. Darauf sollte man sich aber besser nicht verlassen (siehe
        folgender Abschnitt).

                Beachten Sie in diesem Zusammenhang bitte auch unbedingt den Access-Bug in Bezug auf
                WithEvents (“Ein Access-Bug” auf Seite 39).

        Vergleich zweier Objektverweise
        Zum Vergleich zweier Objektverweise dient der Operator Is:
             If objKunde1 Is objKunde2 Then
                Debug.Print "Kunde 1 ist Kunde 2!"
             Else
                Debug.Print "Kunde 1 ist ungleich Kunde 2!"
             End If

        Bestimmen, ob Verweis gesetzt ist
        Manchmal ist es notwendig herauszufinden, ob eine Objektvariable eine gültige Referenz enthält, oder noch
        keiner Instanz zugewiesen wurde. Dies kann mittels eines Vergleichs der Objektvariable mit dem speziellen Wert
        Nothing erreicht werden:

             If objChef Is Nothing Then
                ' ...
             End If

     Die Lebensdauer eines Objekts
        Die Lebensdauer eines Objekts wird nicht wie bei Werttypen durch den Gültigkeitsbereich der Objektv ariablen
        bestimmt. Da Visual Basic eine auf COM basierende Sprache ist (manche sagen, es sei die COM-Sprache
        schlechthin), wird für das Erstellen und Zerstören von Objekten der Mechanismus von COM verwendet. Ein

                                                                                                                               16
AEK 7 – Benutzerdefinierte Klassen im Praxiseinsatz                             Einführung in das Programmieren mit Klassen in VB(A)

        grundlegendes Verständnis dieses Mechanismus ist daher für die saubere Programmierung mit Objekten von
        Nöten.

        Erstellen eines Objekts
        Eine Instanz einer Klasse (ein Objekt) wird mit dem Schlüsselwort New erstellt:
             Set frmKundenA = New Form_frmKunden

        Mit dieser Anweisung werden zwei Dinge initiiert. Zum einen wird mit Hilfe des Schlüsselwortes New eine neue
        Instanz der Klasse Form_frmKunden im Speicher angelegt. Zum anderen verweist nun die Objektvariable
        frmKundenA auf diese neu erstellte Instanz von Form_frmKunden.
        Zu diesem Zeitpunkt wird auch das Ereignis Initialize des Klassenmoduls ausgelöst. Näheres dazu siehe
        Abschnitt "Konstruktion und Destruktion" auf Seite 29.

        Referenzzähler
        Jedes COM-Objekt (und damit auch jedes VB(A)-Objekt) hält einen sogenannten Referenzzähler. Dieser führt
        darüber Buch, wieviele Objektvariablen einen Verweis auf das Objekt halten. Bei jedem Setzen eines Verweises
        auf das Objekt wird der Zähler um 1 erhöht, bei jedem Löschen eines Verweises auf das Objekt wird er um 1
        erniedrigt. Nach einer Zeile Set ... = New ... ist der Referenzzähler des Objekts mit dem Wert 1
        initialisiert.

        Löschen von Objekten
        Objekte können in COM nicht direkt gelöscht werden. Wird jedoch der letzte Verweis auf das Objekt gelöscht,
        erreicht der Referenzzähler den Wert 0 und das Objekt wird automatisch aus dem Speicher entfernt. Verweise
        werden entweder explizit durch Setzen des Verweises auf Nothing oder implizit bei Verlassen des
        Gültigkeitsbereichs der Objektvariablen gelöscht.
        Zu diesem Zeitpunkt wird auch das Ereignis Terminate des Klassenmoduls ausgelöst. Näheres dazu siehe
        Abschnitt "Konstruktion und Destruktion" auf Seite 29.

                Hinweis: Objektverweise sollten immer paarweise gesetzt und wieder gelöscht werden.
                Ausführliche Informationen zu diesem Theme finden Sie im Anhang ("Paarweises Setzen und
                Löschen von Verweisen" auf Seite 48).

        Zirkuläre Referenzen
        Oft ist es praktisch in einer Objekthierarchie bei untergeordneten Objekten eine Parent-Eigenschaft als
        Verweis auf das übergeordnete Element zu haben. Da jedoch fast immer auch das übergeordnete Element einen
        Verweis auf seine Kinder hält, entsteht eine zirkuläre Referenz:

                                                                      Eltern-Objekt
                                      Zirkuläre
                                     Referenzen

                                                      Kind-Objekt 1                       Kind-Objekt 3

                                                                      Kind-Objekt 2

        Das Problem dabei ist nun, dass das Eltern- und seine Kindobjekte einander wechselseitig referenzieren und auf
        diese Art einander am Freigeben der Referenzen und damit am Zerstören der Objekte hindern.

                                                                                                                                 17
AEK 7 – Benutzerdefinierte Klassen im Praxiseinsatz                         Einführung in das Programmieren mit Klassen in VB(A)

        Abhilfe
        Um dennoch eine korrekte Freigabe der reservierten Speicherbereic he zu erhalten, kann eine Methode zum
        Aufbrechen der zirkulären Referenz verwendet werden:

        In der Kind-Klasse:
               Public Sub TearDown()
                  Set mp_objParent = Nothing
               End Sub

        In der Eltern-Klasse:
               Public Sub TearDown()
                  Dim objChild As CCHild

                  For Each objChild In m_collChildren
                     objChild.TearDown
                  Next objChild
               End Sub

        Aufruf von TearDown vor dem Setzen der Objekt-Referenz auf Nothing:
               objTop.TearDown                        ' Alle Parent-Verweise der Kinder löschen
               Set objTop = Nothing                   ' Verweise auf Kinder werden gelöscht

        Nachteilig bei dieser Lösung bleibt, dass es im Verantwortungsbereich des Entwicklers liegt, die Methode zum
        Aufbrechen der zirkulären Referenz (hier: TearDown) auch tatsächlich aufzurufen.

     Syntax für den Zugriff auf Elemente
        Im Folgenden wird die Syntax des Zugriffs auf die unterschiedlichen Element-Typen eines Objekts besprochen.

        Eigenschaften
        Eigenschaften eines Objekts werden in VB mit Hilfe des Punkt-Operators angesprochen4:
               .

        Der Zugriff auf eine Eigenschaft kann im Allgemeinen schreibend und lesend erfolgen. Bei der Erstellung
        benutzerdefinierter Klassen kann der Zugriff aber auch nur schreibend oder nur lesend gestaltet werden.

        Beispiele:
        Schreibzugriff auf die Eigenschaft Caption des Objekts lblInfo:
               lblInfo.Caption = "Keine weiteren Datensätze vorhanden."

        Lesezugriff auf die Eigenschaft Column des Objekts cmdKunden:
               strMsg = "Kunde " & cmbKunden.Column(2) & " wird nun gelöscht."

        Die Eigenschaft Column des Listbox- (und damit auch des Kombinationsfeld-) Steuerelements in Access ist
        übrigens der eher seltene Fall einer parametrisierten Eigenschaft, die darüber hinaus auch noch einen optionalen
        Parameter verwendet. Genaueres dazu siehe Abschnitt "Parametrisierte Eigenschaften" auf Seite 27.

        4   Erklärungen zur Syntax-Beschreibung siehe Anhang "Syntax-Auszeichnungen" auf Seite 48.

                                                                                                                             18
AEK 7 – Benutzerdefinierte Klassen im Praxiseinsatz                         Einführung in das Programmieren mit Klassen in VB(A)

        Methoden
        Methoden eines Objekts werden ebenfalls über den Punkt-Operator angesprochen:
             .([])

        Beispiele:
        Aufruf der parameterlosen Methode SetFocus des Objekts txtNachname:
             txtNachname.SetFocus

        Aufruf (mit Parameterübergabe) der Methode OpenForm des Objekts DoCmd:
             DoCmd.OpenForm "frmKunden"

        Ereignisse
        Wenn auf die von einem Objekt ausgelösten Ereignisse reagiert werden soll, muss die Deklaration der
        Objektvariablen um das Schlüsselwort WithEvents ergänzt werden:
             Dim WithEvents  As 

        Tritt nun ein Ereignis ein, wird – sofern vorhanden – eine wie folgt aufgebaute Ereignis-Prozedur aufgerufen:
             Sub _([])

        Beispiele:
        Ereignisprozedur für das Ereignis Click des Objekts cmdClose:
             Private Sub cmdClose_Click()
                DoCmd.Close acForm, Me.Name
             End Sub

        Abfangen des Ereignisses Close einer Instanz von Word.Document:
             Private WithEvents m_docWord As Word.Document
             ' ...
             Private Sub m_docWord_Close()
                DbLogger.Log m_docWord.FullName
             End Sub

                Beachten Sie hier bitte unbedingt den Access-Bug in Bezug auf WithEvents (“Ein Access-Bug” auf
                Seite 39).

     Standard-Element
        Jede Klasse kann eine Eigenschaft oder Methode als Standard-Element kennzeichnen. In diesem Fall kann beim
        Zugriff die Angabe des Namens des Standard-Elements entfallen.

        Beispiel:
        Zugriff auf die Standard-Eigenschaft "Caption" eines Label-Steuerelements "lblInfo":
             ' (Optionale) Angabe des Standard-Elements
             lblInfo.Caption = "Es sind noch drei Plätze frei."
             ' Ohne Angabe des Standard-Elements
             lblInfo = "Es sind noch drei Plätze frei."

                                                                                                                             19
AEK 7 – Benutzerdefinierte Klassen im Praxiseinsatz                        Einführung in das Programmieren mit Klassen in VB(A)

        Die Unterscheidung, ob das Objekt selbst, oder sein Standard-Element gemeint ist, kann nur anhand der Art der
        Zuweisung erfolgen. Bei einer Zuweisung mit Set ist das Objekt, ohne Set das Standard-Element gemeint:
             Dim txtCurrent As Access.TextBox
             Dim strValue As String

             Set txtCurrent = Me.txtNachname             ' Das Objekt selbst
             strValue = Me.txtNachname                   ' Das Standard-Element (Value)

        Das Standard-Element kann auch eine Methode sein. In diesem Fall ruft die Angabe des Namens des Objekts
        allein diese Standard-Funktion bzw. -Prozedur auf.

  Access-Objekte
        Bei der Entwicklung mit Hilfe von Ereignisprozeduren in Access werden an vielen Stellen Objekte verwendet.
        Dies fällt manchmal gar nicht sonderlich auf, weil die Objekte meistens ein Oberflächen-Element kapseln.
        Insbesondere die Instanziierung dieser Objekte bleibt hier dem Entwickler verborgen. Die Objekte sind einfach
        da, weshalb man sie meist kaum von den zugehörigen Oberflächenelementen trennt. Dieser Abschnitt soll vor
        allem den Unterschied zwischen den Oberflächen-Elementen und den dem Entwickler zur Verfügung stehenden
        Instanzen der jeweiligen Kapsel-Klassen verdeutlichen.

        Bei folgender häufig verwendeten Ereignisprozedur eines Formulars sind beispielsweise drei verschiedene
        Objekte beteiligt:
             Private Sub cmdClose_Click()
                DoCmd.Close acForm, Me.Name
             End Sub

        Me
        Me ist der Name einer Referenz auf das Objekt der Formularklasse des vorliegenden Formulars. Der Name der
        Formularklasse ist Form_. Hat das Formular beispielsweise den Namen frmKunden, so ist
        der Name der von Access generierten Formular-Klasse Form_frmKunden. Hingegen ist Me die Referenz auf
        jene Instanz der Formularklasse, die das vorliegende Formular kapselt. Die spezielle Formularklasse (wie das
        genannte Beispiel Form_frmKunden) basiert auf der generischen Access-Formularklasse Form. Diese
        generische Klasse wird durch folgende Elemente erweitert:
              · Die Felder der zugrunde liegenden Datensatzherkunft (Eigenschaft RecordSource)
                  Für jedes Feld der zur Entwurfszeit bekannten Datensatzherkunft wird eine Eigenschaft angelegt
                  (Verborgener Datentyp AccessField aus der Bibliothek Access, einziges Element ist die
                  Standardeigenschaft Value).
              · Die Steuerelemente
                  Für jedes eingefügte Steuerelement wird eine gleichnamige Eigenschaft erzeugt. Der Datentyp
                  entspricht der jeweiligen Kapselklasse.

        Das Bewusstsein über diese Zusammenhänge bietet interessante Möglichkeiten für die Access-Praxis. Elemente
        einer benutzerdefinierten Klasse können auch dem Objektmodul eines Formulars oder Berichts hinzugefügt
        werden. So kann ein Kunden-Formular zum Beispiel mit einer Eigenschaft KundenID ausgestattet werden.
        Durch entsprechende Programmierung kann nun einfach durch Zuweisen eines gültigen Primärschlüsselwertes
        an die Eigenschaft KundenID der entsprechende Datensatz im Formular angezeigt werden.

                                                                                                                            20
Sie können auch lesen