Ohne Klassen und Objekte läuft in .NET gar nichts mehr – und das gilt für Visual Basic nicht weniger als für alle die anderen .NET-Programmiersprachen. Dass Visual Basic lange Zeit als nicht objektorientierte Programmiersprache galt, stimmte selbst zu Visual Basic 6.0-Zeiten nur teilweise – denn selbst diese Version von Visual Basic nutzte schon beispielsweise Schnittstellen (Interfaces) zur COM-Entwicklung recht intensiv, auch wenn es regelrechte Vererbung nicht und Polymorphie nur durch späte Bindung emuliert gab.
Objektorientierte Programmierung (OOP) ist aber wichtig für viele, viele Aspekte, und die wichtigsten dabei sind:

  • Sie spart Entwicklungskosten

    Nur mit angewandter OOP-Entwicklung lassen sich sinnvoll wieder-verwendbare Komponenten entwickeln. Softwareentwicklungsabteilungen oder Independent Software Vendors (ISV) investieren damit in die Zukunft. OOP-Komponenten stellen ihr wirkliches Kapital dar, da mit jedem erfolgreich fertig gestellten Projekt Komponenten entstehen, die die Entwicklungskosten des nächsten Projekts deutlich reduzieren.

  • Sie reglementiert Entwicklungsteams bei der Zusammenarbeit, und zwar nicht auf bevormundende, diktierende, sondern auf helfende und unterstützende Art und Weise. Teams können Code für andere Teams vorbereiten und durch Objektmodelle so gestalten, dass Code von Team A nahtlos mit Code von Team B zusammenlaufen wird, ohne dass beide Teams während der Entwicklung ständig zusammenar-beiten müssen. Teams können sogar Klassen entwickeln, die imstande sind, Code zu verarbeiten, der erst Jahre später entwickelt wird – und garantieren, dass dieser noch nicht existierende Code reibungslos seinen Dienst verrichten wird.

  • Sie sorgt für robusten Code. Objektorientierte Programmierung in .NET macht Ihre Anwendung verlässlich, absturzsicher und robust, solange man sich an bestimmte Regeln hält: Späte Bindung – also das Zulassen des Kompilierens von Eigenschaften oder Methoden für Objektvariablen, die Nachkömm-linge ihrer Klassentypen enthalten – sollte man in Visual Basic nur in Ausnahmefällen erlauben. Auf diese Weise verhindert das Typsystem von .NET, dass – etwa wie in C++ möglich – zur Laufzeit der Versuch fehlschlägt, eine Variable vom Typ »JPEG-Bild« als Zeichenkette zu verwenden, wodurch eine Anwendung instabil werden könnte oder sich durch Pufferüberläufe vielleicht sogar dazu missbrauchen ließe, Schadcode auszuführen.

Was ist eine Klasse?

Versetzen Sie sich in Ihre Kindheit zurück. Und zwar so weit, dass Sie sich vorstellen können, im Sandkasten zu sitzen und mit Förmchen und nassem Sand zu spielen. Oder, falls es in Ihrer Vorstellung keinen Sandkas-ten gibt, mit Förmchen und Knete . Sie werden es nicht glauben, aber genau zu diesem Zeitpunkt haben Sie bereits das Klassenkonzept das erste Mal angewendet. Ein Förmchen ist im Grunde genommen nämlich nichts anderes als eine Klasse. Das Förmchen gibt vor, wie Objekte ausschauen sollen, die aus ihm entstehen werden, aber selbst ist es noch kein Objekt, sondern nur eine Vorlage. Wenn Sie aus einer Klasse (einem Förmchen) einen Sand- oder Knetekuchen (ein Objekt) machen wollen, dann müssen Sie ein Objekt dieser Klasse instanziieren. Um bei der Analogie zu bleiben: Sie instanziieren einen Kuchen aus einem Förmchen, indem Sie nassen Sand oder Knete in das Förmchen hineingeben, das ganze Ding umdrehen und das Förmchen abziehen.

Sogar Kinder spielen objektorientiert und bilden Instanzen. Indem sie nämlich Knete in ein Förmchen geben…

 

Klassen in .NET Framework sind natürlich etwas abstrakter, aber Sie machen sich daran auch nicht die Hände schmutzig. Sie bestehen erst einmal aus einer Reihe von sogenannten Feldvariablen – auch Felder oder Membervariablen genannt – und der Klassenrumpfdefinition, die diese Variablen einschließt und der Klasse ihren Namen gibt.
Damit existiert dann bereits die einfachste Version einer Klasse, die, wie wir gleich sehen werden, ihre Daten logisch kapselt. Immerhin erlaubt sie uns schon, das Problem unseres ersten Beispielpro¬gramms im Ansatz zu ersticken – die zweite Version dieses Demoprogramms stellt das unter Beweis. Hier gibt es nun eine Klasse namens Kontakt, die aus vier Feldern besteht – die vier Datenfelder, die eine einzige Adresse ausmachen. In der Folge benötigen wir nun nicht mehr vier eigentlich völlig zusammenhanglose Arrays, sondern nur noch ein einziges Array , das aus Elementen besteht, die jeweils eine komplette Adresse spei-chern.

   … und dann die Methode »Zusammenpressen« anwenden, …

 

Um das zu erreichen, fügen wir dem bestehenden Programm einfach eine neue Codedatei hinzu – eine Klassendatei – namens Kontakt.vb. In diese Klassencodedatei schreiben wir dann folgende Zeilen:


Public Class Kontakt
    Public Nachname As String
    Public Vorname As String
    Public PLZ As String
    Public Ort As String
End Class


Diese Klasse namens Kontakt stellt die einfachste Form einer Klasse dar. Sie enthält nur vier öffentlich zugängliche Felder, aber die Klasse fasst eben diese vier Felder logisch zu einem Datensatz zusammen.



… erhalten sie ganz viele kleine Knetaffen, oder in Programmiererdeutsch ausgedrückt: Aus der Klasse »Affe« bilden sie viele Instanzen, die dann alle unterschiedliche Eigenschaften haben können. In diesem Beispiel können sich die Instanzen durch ihre Farbeigenschaft (engl: color property) unterscheiden, obwohl sie alle von derselben Klasse (nämlich dem Förmchen) abstammen.

Klassen mit New instanziieren

Um eine so genannte Instanz dieser Klasse zu schaffen, bedient man sich des Schlüsselwortes New – intern wird damit der entsprechende Speicherplatz geschaffen, den man benötigt, um die Daten der Feldvariablen der Klasse im Arbeitsspeicher  abzulegen. Eine Objektvariable, die man zuvor als Typ dieser Klasse definiert, dient dann dazu, auf die Elemente der Klasseninstanz zuzugreifen. Die Anwendung dieser einfachen Bei-spielklasse würde also wie folgt aussehen:


Dim adr As Kontakt
adr = New Kontakt


Die erste Codezeile legt eine Objektvariable vom Typ Kontakt an und die zweite Codezeile weist ihr eine neue Instanz zu. Sie können diese beiden Zeilen auch in einer Zeile zusammenfassen:


Dim adr As New Kontakt


Anschließend verwenden Sie die Instanz dieser Klasse mithilfe der definierten Objektvariablen, um auf die einzelnen Felder zuzugreifen:


adr.Nachname = "Dröge"
adr.Vorname = "Ute"
adr.PLZ = "59555"
adr.Ort = "Lippstadt"


Um nochmals auf unsere Analogie mit der Knete zurückzukommen: Die Objektinstanz entspricht hier einem Knetkuchen, der aus einem Förmchen hervorgegangen ist. Die Klasse hingegen ist das Förmchen. Die Objektvariable benennt wiederum den Knetekuchen, der aus dem Förmchen hervorgegangen ist, und natürlich können Sie, wie aus dem Förmchen, beliebig viele Sandkucheninstanzen erstellen. Beliebig viele? Nicht ganz: Natürlich nur so viele, bis der »verwaltete Sandberg« zuneige geht, aus dem Sie die Sandkuchen machen, der in der Analogie dem Managed Heap entspricht, aus dem Sie den Speicherplatz für Ihre Objektinstanzen beziehen.


Ein gern gemachter Fehler am Anfang ist es übrigens, die Klasse nicht zu instanziieren, sondern direkt verwenden zu wollen:

'So geht’s natürlich nicht!
Kontakt.Nachname = "Dröge"
Kontakt.Vorname = "Ute"
Kontakt.PLZ = "59555"
Kontakt.Ort = "Lippstadt"

Warum? – Denken Sie mal drüber nach. In Analogie zu einer primitiven Variablen würden Sie praktisch statt

Dim i as Integer
i = 5

einfach

Integer = 5

schreiben, quasi den Bezeichner für den Datentyp als Variablennamen verwenden. Das geht natürlich nicht! Später werden wir sehen, dass es tatsächlich Eigenschaften und Methoden gibt, die Sie direkt über den Typennamen aufrufen können wie etwa bei if File.Exists("C:\windows\calc.exe") then – aber dabei handelt es sich um so genannte statische Methoden, die wir später als Ausnahme von der Regel betrachten werden.


Öffentliche Felder oder Eigenschaften beim Instanziieren initialisieren


Visual Basic erlaubt seit der Version 2008 auch eine kürzere Variante beim Vorbelegen der Felder bzw. Eigenschaften mit Werten: Sie können öffentliche Felder oder Eigenschaften direkt beim Instanziieren mithilfe des With-Schlüsselwortes definieren, wie im folgenden Beispiel zu sehen:


Dim adr As New Kontakt With {.Nachname = "Dröge", _
                        .Vorname = "Ute", .PLZ = "59555", .Ort = "Lippstadt"}

 

New oder nicht New – wieso es sich bei Objekten um Verweistypen handelt

Zum besseren Verständnis für alle späteren Kapitel ist es überaus sinnvoll, ein paar Worte zur Speicherung von Objekten, also Instanzen von Klassen zu verlieren. Objektvariablen und Objekte sind nämlich nicht so miteinander verbunden, wie man es sich zunächst vielleicht vorstellt. Im Gegenteil: Der Verbund einer Objektvariablen mit den eigentlichen Daten des Objekts hält bestenfalls so gut wie eine Prominen¬ten¬ehe: Was auf den ersten Blick so innig und für immer geschaffen zu sein scheint, ist in der nächsten Sekunde auch schon wieder sauber getrennter Schnee von gestern.

Durch das Instanziieren wird ein Teil vom Hauptspeicher weggenommen und beim Instanziieren den neuen Objekten zur Verfügung gestellt,
die dann auf dem Managed Heap (etwa: »verwalteter Haufen«) unter Beobachtung gestellt werden.

Die Wahrheit ist nämlich: Eine Objektvariable speichert im Grunde genommen nur einen Speicheradressen-zeiger (oder einfach nur kurz Zeiger genannt) auf die eigentlichen Daten in einem besonders überwachten Teil des Hauptspeichers, dem so genannten Managed Heap. In eben diesen gelangen die Daten der Objekte, die Sie mithilfe von New aus Klassen instanziieren.

 

Objektvariablen sind im Grunde nichts anderes als Klebehefter, die ein Objekt (also eine Instanz eines Objekts) bezeichnen. Und natürlich können Sie an ein Äffchen zwei Klebehefter zum Bezeichnen hängen, oder im Programmiererdeutsch ausgedrückt: Mehrere Objektvariablen können auf dieselbe Instanz zeigen.

Und wie wir (die Älteren unter uns jedenfalls) aus unseren Anfängertagen mit dem Commodore 64, Atari ST, Amiga und Maschinensprache noch alle wissen, untergliedert sich der Arbeitsspeicher eines Computers in bestimmte Speicherbereiche, die alle bestimmte »Hausnummern« (die Speicher¬adressen) besitzen.
Wenn Sie nun ein Objekt aus einer Klasse erstellen – zum Beispiel indem Sie einen Kontakt-Datentyp  mit New in die Objektvariable objVarKontakt instanziieren –, dann legt .NET Framework die Daten für diese Objektinstanz beispielsweise an Speicheradresse 460.386 auf dem Managed Heap ab, und die Objektvariable wird intern sozusagen zu einer Integer-Variablen (oder auf 64-Bit-Systemen zu einer Long-Variablen), die diese Adresse trägt.



Diese Tatsache hat aber entscheidende Folgen, wie das folgende Beispiel gleich zeigen wird.

Laden Sie sich dazu die Beispieldateien hier herunter und öffnen Sie die Projektmappe (.sln).

 

Module Module1

    Sub Main()

        'Instanziieren mit New und dadurch
        'Speicher für das Kontakt-Objekt
        'auf dem Managed Heap anlegen.
        'Instanz gleichzeitig mit Daten initialisieren.
        Dim objVarKontakt As New Kontakt With {.Nachname = "Pfeiffer", _
                .Vorname = "Ute", .PLZ = "59555", .Ort = "Lippstadt"}

        'Nur Objektvariable anlegen,
        'es wird aber kein Speicher reserviert!
        Dim objVarKontakt2 As Kontakt

        'objVarKontakt2 "zeigt" ab jetzt auf
        'dieselbe Instanz wie objVarKontakt
        objVarKontakt2 = objVarKontakt

        'Und das kann man auch beweisen:
        'Das Ändern der Instanz geschieht...
        objVarKontakt2.Nachname = "Dröge"

        'durch beide Objektvariablen, die natürlich
        'auch dasselbe widerspiegeln.
        Console.WriteLine(objVarKontakt.Nachname)

        Console.WriteLine()
        Console.WriteLine("Zum Beenden Taste drücken")
        Console.ReadKey()
    End Sub

End Module

Public Class Kontakt
    Public Vorname As String
    Public Nachname As String
    Public PLZ As String
    Public Ort As String
End Class

 

Wenn Sie dieses Beispiel laufen lassen, erhalten Sie die Ausgabe


Dröge

Zum Beenden Taste drücken

 



Das Kopieren einer Objekt¬variablen in eine andere Objektvariable kopiert nur den Zeiger auf die Instanz – die dann durch beide Variablen manipulierbar und abrufbar wird.

Beachten Sie, dass es in diesem Beispiel zwar nur eine einzige Dateninstanz der Klasse Kontakt gibt, die jedoch durch zwei Objektvariablen angesprochen und damit auch widergespiegelt wird: Beim Instanziieren wird die Adresse des Speichers, an der die Daten der Instanz abgelegt werden, in der Objektvariablen objVarKontakt gespeichert. Diese Adresse wird in die Variable objVarKontakt2 übertragen und, wichtig, hierbei wird nicht etwa eine Kopie der gesamten Instanz im Managed Heap angelegt!
Eine Objektvariable »zeigt« also quasi auf die Daten, die sie verwaltet. In anderen Programmiersprachen wie C++ gibt es zu diesem Zweck besondere Variablen, die wie schon erwähnt, auch als (Speicheradressen )Zeiger bezeichnet werden. In Visual Basic wird eine Objektvariable, die die Instanz einer Klasse verwaltet, automa-tisch zu einem solchen Zeiger.


Dieses Verhältnis zwischen Objektvariable und eigentlichem Objekt (eigentlicher Instanz) sollten Sie sich gut einprägen, da dieses einerseits die Quelle schwer zu findender Fehler ist – schließlich kann es auch versehentlich passieren, dass wenn Sie nicht aufpassen, eine Objektvariable die Instanz eines Objekts verän-dert, die eigentlich und ausschließlich durch eine ganz andere Objektvariable angesprochen werden sollte. Andererseits kann Ihnen dieses Verhältnis auch zum Vorteil gereichen, nämlich wenn es darum geht, nicht Objekte zu kopieren, sondern nur die Zeiger auf diese – beispielsweise wenn es beim Sortieren großer Objektmengen auf Geschwindigkeit ankommt und deswegen keine ganzen Speicherblöcke mit den eigentli-chen Daten, sondern nur die Zeiger auf die Objektinstanzen kopiert werden sollen.

kick it on dotnet-kicks.de

Mehr zu diesem Thema in: Visual Basic 2010 das Entwicklerbuch von Klaus Löffelmann, erhältlich bei Amazon auch auf Englisch, und bei Microsoft Press. Möchten Sie Klaus Löffelmann oder das ActiveDevelop-Team für professionelle Software-Entwicklungsprojekte (Migration, C#, Visual Basic.NET) buchen, informieren Sie sich auf www.activedevelop.de

klauslo am 06. Dezember 2011

Tags: , , , | Categories: Entwicklung | Einführung in OOP