Praxiseinsatz von benutzerdefinierten Klassen in Microsoft Access
←
→
Transkription von Seiteninhalten
Wenn Ihr Browser die Seite nicht korrekt rendert, bitte, lesen Sie den Inhalt der Seite unten
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