3.15 Schnittstellen: Interface und Implements 

Kommen wir nun zur zweiten Art der Vererbung in Visual Basic. Sie legt nur eine Schnittstelle fest, ist also eine reine Form ohne Inhalt. Aus der Inhaltslosigkeit ergibt sich:
Von einer Schnittstelle können keine Objekte erzeugt werden. |
Diese rein formelle Festlegung wird durch einen neuen Datentyp kenntlich gemacht, der Schnittstelle (engl. Interface) genannt wird. Durch sie wird ein Vertrag angeboten, der nur in einer Klasse erfüllt werden kann. Dabei legt die Klasse durch Deklaration fest, dass und wie sie ihn erfüllt.
Eine Schnittstelle ist im Wesentlichen wie eine Klasse aufgebaut, darf aber ausschließlich die in der folgenden Syntax gelisteten Elemente und Modifikatoren enthalten (die letzte Möglichkeit hat eigentlich nichts mit der Idee von Schnittstellen zu tun, siehe Abschnitt 3.8, »Innere Klassen«). Optionale Teile sind in eckige Klammern gesetzt und Alternativen durch einen senkrechten Strich | getrennt. Kursiv gesetzte Teile müssen Sie Ihren Bedürfnissen anpassen. Wie üblich fasst ein Unterstrich zwei Zeilen zu einer logischen Zeile zusammen. Die Typen-Spezifikation wird im Abschnitt 4.4, »Generisches«, erläutert.
[Friend|Public] Interface IName[Typen] |
Dabei möchte ich auf folgende Besonderheiten hinweisen:
- Der Name der Schnittstelle sollte mit dem Buchstaben I beginnen, um sie leichter von Klassen zu unterscheiden und damit einige später zu besprechende Konzepte leichter zu realisieren sind (siehe zum Beispiel Erweiterungsattribute in Abschnitt 4.8, »Attribute«).
- Schnittstellen enthalten nie Anweisungen oder End-Konstrukte.
- Schnittstellenmitglieder haben nie Sichtbarkeitsmodifikatoren, sie sind implizit öffentlich.
- Schnittstellenmitglieder sind nie mit Shared klassengebunden.
- Schnittstellen enthalten nie Felder oder Operatoren.
- Schnittstellen dürfen leer sein (Markerschnittstellen).
- Eine Aufteilung mit Partial ist nicht erlaubt.
- Typdefinitionen in einer Schnittstelle stellen keinen von einer Klasse zu konkretisierenden Vertrag dar, sondern sind »einfach« geschachtelte Typen (siehe Abschnitt 3.8, »Innere Klassen«).
Einige dieser Beschränkungen sind notwendigerweise mit dem Konzept einer Schnittstelle verbunden, wie zum Beispiel das Fehlen von Anweisungen. Andere sind einfach so in der Sprachdefinition von Visual Basic festgelegt.
Kommen wir nun dazu, wie eine Klasse von einer Schnittstelle Gebrauch macht. Dazu deklariert sie mittels Implements, dass die Klasse die Schnittstelle konkretisiert. Außerdem wird an jedem Klassenmitglied vermerkt, wenn es ein Schnittstellenmitglied implementiert. In der folgenden Syntax sind optionale Teile in eckige Klammern gesetzt und kursiv gesetzte Teile müssen Sie Ihren Bedürfnissen anpassen. Wie üblich fasst ein Unterstrich zwei Zeilen zu einer logischen Zeile zusammen. Die Typen-Spezifikation wird im Abschnitt 4.4, »Generisches«, erläutert.
Class Klasse |
Als Modifikatoren sind weniger erlaubt als bei allgemeinen Methoden und Eigenschaften (siehe Tabelle 3.26).
Art | Beschreibung |
Sichtbarkeit |
Grad der Öffentlichkeit (siehe Abschnitt 3.2, »Kapselung«) |
Redefinition |
Art des Ersatzes oder Zwangs zu einer Definition (siehe Abschnitt 3.13.4, »Modifikation: Shadows und Overloads (Overrides)«, Abschnitt 3.13.5, »Abstrakte Klassen: MustInherit und MustOverride«, Abschnitt 3.14.1, »Virtuelle Methoden: Overridable und Overrides« und Abschnitt 3.3.4, »Überladung«) ohne: NotOverridable. |
Die Implementation einer Schnittstelle erweitert den Datentyp eines Objekts:
Ein Objekt einer Klasse, die eine Schnittstelle implementiert, ist (unter anderem) vom Typ der implementierten Schnittstelle. |
Auch bei der Implementation einer Schnittstelle gibt es ein paar Besonderheiten:
- Eine Klasse darf, im Gegensatz zur Vererbung, mehrere Schnittstellen implementieren.
- Ein Klassenmitglied kann beliebig viele Schnittstellenmitglieder zugleich implementieren.
- Es müssen alle Schnittstellenmitglieder implementiert werden (gegebenenfalls über Vererbung).
- Dasselbe Schnittstellenmitglied darf nicht mehrfach implementiert werden.
- Implementierende Klassenmitglieder sind nie mit Shared klassengebunden.
- Externe Funktionen können nie eine Schnittstelle implementieren.
- Namen von Schnittstellenmitgliedern und implementierenden Klassenmitgliedern dürfen unterschiedlich sein.
- Parametertypen in der Schnittstelle und der implementierenden Klasse sind identisch.
- Öffentliche Schnittstellenmitglieder können von privaten Klassenmitgliedern implementiert werden (meiner Meinung nach ein unglückliches Sprachdesign).
Als Beispiel dient der Vertrag der Bürger eines Staates mit den Finanzbehörden. Da alle Steuern zahlen müssen, aber nicht jeder in derselben Art und Weise, bietet es sich an, die Verpflichtung, dass zu zahlen ist, in einer Schnittstelle IBürger zu deklarieren und erst in den implementierenden Klassen festzulegen, wie bezahlt wird. Dazu deklarieren die Klassen Bauer und Händler mit Implements IBürger, dass sie die Schnittstelle implementieren. Zusätzlich wird die implementierende Methode mit IBürger.SteuernZahlen markiert. In einer Klasse, die mehrere passende Methodensignaturen bereitstellt, ist dies logisch notwendig und wird von Visual Basic zwecks Konsistenz immer gefordert. Die verschiedenen Implementierungen reflektieren die unterschiedlichen Arten, Steuern zu zahlen. Die Methode Test() schließlich greift auf die verschiedenen Steuerzahler über den Typ der Schnittstelle zu.
Hinweis |
Um die Beispiele einfach zu halten, enthalten sie nur je ein Schnittstellenmitglied. Im Allgemeinen kann eine Schnittstelle viele Mitglieder haben, inklusive der überladenen. |
'...\Klassendesign\Schnittstellen\Prinzip.vb |
Option Strict On
Namespace Klassendesign
Interface IBürger
Sub SteuernZahlen()
End Interface
Class Bauer : Implements IBürger
Sub Steuern() Implements IBürger.SteuernZahlen
Console.WriteLine("Bauer zahlt in Naturalien.")
End Sub
End Class
Class Händler : Implements IBürger
Sub SteuernZahlen() Implements IBürger.SteuernZahlen
Console.WriteLine("Händler zahlt mit Geld.")
End Sub
End Class
Module Prinzip
Sub Test()
For Each z As IBürger In New IBürger() {New Händler(), New Bauer()}
z.SteuernZahlen()
Next
Console.ReadLine()
End Sub
End Module
End Namespace
Die Ausgabe zeigt, wie Händler und Bauer, als IBürger angesprochen, Steuern zahlen:
Händler zahlt mit Geld.
Bauer zahlt in Naturalien.
Hinweis |
.NET arbeitet oft mit Schnittstellen, wie zum Beispiel IEnumerable und IDisposable, aber leider nicht ganz konsequent. Zum Beispiel setzt die For Each-Schleife nicht unbedingt IEnumerable voraus, sondern es reicht eine zugängliche Methode der Signatur Function GetEnumerator() As Collections.IEnumerator. |
3.15.1 Benennungen und Parameter 

Die Namen der implementierenden Klassenmitglieder werden meist so gewählt wie die der Schnittstellenmitglieder. Dies ist aber nicht zwingend und sehr nützlich, wenn dasselbe Klassenmitglied gleichzeitig verschiedennamige Mitglieder mehrerer Schnittstellen implementieren soll. Das folgende Codefragment zeigt die zwei Schnittstellen ITransporter und IAuto, die für die Eigenschaft der maximalen Zuladung die beiden verschiedenen Namen Nutzlast() und Beladung() wählen. Da dasselbe Fahrzeug dieselbe Zuladung hat, egal ob Sie es als Transporter oder Auto ansehen, werden beide Schnittstellenmethoden in der Klasse LKW in einer einzigen Eigenschaft Zuladung() implementiert. Die Methode Test() zeigt, dass der Typ einer Variablen den Namen der Eigenschaft bestimmt.
'...\Klassendesign\Schnittstellen\Benennungen.vb |
Option Strict On
Namespace Klassendesign
Interface ITransporter
ReadOnly Property Nutzlast() As Integer
End Interface
Interface IAuto
ReadOnly Property Beladung() As Integer
End Interface
Class LKW : Implements ITransporter, IAuto
Public ReadOnly Property Zuladung() As Integer _
Implements IAuto.Beladung, ITransporter.Nutzlast
Get
Return 1000
End Get
End Property
End Class
Module Benennungen
Sub Test()
Dim lkw As LKW = New LKW() : Dim trans As ITransporter = lkw
Console.WriteLine("Zuladung {0}", lkw.Zuladung)
Console.WriteLine("Zuladung {0}", trans.Nutzlast)
Console.ReadLine()
End Sub
End Module
End Namespace
Beide Variablen greifen auf dasselbe Objekt zu und liefern dieselbe Last, egal wie sie genannt wird.
Zuladung 1000
Zuladung 1000
Bei der Implementierung mehrerer Ereignisse in demselben Ereignis gibt es noch eine kleine Stolperfalle. Dies ist nur möglich, wenn die Ereignisse identisch dasselbe Delegate verwenden. Da ein Ereignis ohne As-Klausel implizit ein neues Delegate definiert, können also nur solche Ereignisse in einem einzigen Ereignis implementiert werden, die mit einer As-Klausel dasselbe Delegate spezifizieren. Das folgende Codefragment zeigt zwei Schnittstellen, IAusbilder und ITrainer, mit einem Ereignis, das dessen Typ über ein Delegate festlegt und eine Schnittstelle IChorleiter, die den Ereignistyp implizit definiert. Die beiden ersten Ereignisse werden in der Klasse Lehrer in einem einzigen Ereignis implementiert. Dies ist beim Ereignis der dritten Schnittstelle nicht möglich, und es wird in einem zusätzlichen Ereignis implementiert.
'...\Klassendesign\Schnittstellen\Ereignisse.vb |
Option Strict On
Namespace Klassendesign
Delegate Sub Aufruf()
Interface IAusbilder
Event Anwesend As Aufruf
End Interface
Interface ITrainer
Event Zählen As Aufruf
End Interface
Interface IChorleiter
Event Stimmen()
End Interface
Class Lehrer : Implements IAusbilder, ITrainer, IChorleiter
Event Appell As Aufruf Implements IAusbilder.Anwesend, ITrainer.Zählen
Event Appell2() Implements IChorleiter.Stimmen
...
End Class
...
End Namespace
Keine Wahl besteht hingegen bei den Typen. So kann zum Beispiel aus einer Eigenschaft einer Schnittstelle nicht eine implementierende Methode in einer Klasse werden. Auch müssen die Typen von Parametern erhalten bleiben, inklusive der Standardwerte optionaler Parameter. Das nächste Beispiel berechnet den Einkommenssteuersatz in Abhängigkeit von den optionalen Einnahmen. Der Standardwert ist so gewählt, dass ohne Einkommensangabe der Höchststeuersatz gilt. Die implementierende Klasse Angestellter muss diesen Standardwert übernehmen. Jeder andere Wert verursacht einen Compilerfehler.
'...\Klassendesign\Schnittstellen\Parameter.vb |
Option Strict On
Namespace Klassendesign
Interface ISteuerzahler
Function Steuersatz(Optional ByVal einkommen As Int32 = 250000) As Int32
End Interface
Class Angestellter : Implements ISteuerzahler
Function Steuersatz(Optional ByVal einkommen As Int32 = 250000) _
As Int32 Implements ISteuerzahler.Steuersatz
If einkommen < 7664 Then Return 0
Dim d As Integer = 12740 – 7664
If einkommen < 12740 Then Return 15 + (einkommen – 7664) / d * 9
d = 52152 – 12740
If einkommen < 52152 Then Return 24 + (einkommen – 12740) / d * 18
If einkommen < 250000 Then Return 42
Return 45
End Function
End Class
Module Parameter
Sub Test()
Dim an As Angestellter = New Angestellter()
For Each ein As Integer In New Integer() {7000, 10000, 20000, 40000}
Console.WriteLine("{1}% Steuern bei {0}", ein, an.Steuersatz(ein))
Next
Console.WriteLine("{0}% Steuern ohne Angabe", an.Steuersatz())
Console.ReadLine()
End Sub
End Module
End Namespace
Die Ausgabe bestätigt die korrekte Arbeitsweise:
0% Steuern bei 7000
19% Steuern bei 10000
27% Steuern bei 20000
36% Steuern bei 40000
45% Steuern ohne Angabe
Hinweis |
Die Parametertypen (inklusive ByVal/ByRef) und gegebenenfalls Standardwerte in der Schnittstelle und der implementierenden Klasse müssen identisch sein. Selbst implizite (erweiternde) Typumwandlungen werden nicht berücksichtigt. |
3.15.2 Schnittstellen und Vererbung 

Geerbte Schnittstellenimplementierungen
Ist eine Schnittstelle einmal implementiert, vererbt sich diese Tatsache auch auf alle Kindklassen, so als sei die Schnittstelle in der Kindklasse implementiert worden. Das folgende Beispiel verwendet die folgende Vererbungshierarchie:
IHaus
+-Haus
+-Bude
+-Villa
Die Schnittstelle IHaus hat zwei Methoden, die in der Klasse Haus implementiert werden. Dann wird von Haus die Klasse Bude abgeleitet, ohne Haus zu ändern oder zu ergänzen (die Angabe von Implements IHaus ist optional). Dagegen wird in der Klasse Villa eine der beiden Methoden neu implementiert. Dies ersetzt nur diese eine Signatur, ohne die andere zu beeinflussen. In der Methode Test() werden eine Villa und eine Bude über die Basisklassenreferenz Haus genutzt.
'...\Klassendesign\Schnittstellen\Vererbung.vb |
Option Strict On
Namespace Klassendesign
Interface IHaus
Overloads Sub Wand(ByVal material As String)
Overloads Sub Wand(ByVal kostenrahmen As Double)
End Interface
Class Haus : Implements IHaus
Overridable Sub Wand(ByVal material As String) Implements IHaus.Wand
Console.WriteLine("Wanddicke Haus " & If(material = "Beton", 20, 25))
End Sub
Overridable Sub Wand(ByVal kostenrahmen As Double) Implements IHaus.Wand
Console.Write("Materialwahl Haus : ")
Wand(If(kostenrahmen <= 15, "Beton", "Stein"))
End Sub
End Class
Class Bude : Inherits Haus : End Class
Class Villa : Inherits Haus : Implements IHaus
Overrides Sub Wand(ByVal kostenrahmen As Double) Implements IHaus.Wand
Console.Write("Materialwahl Villa: ")
Wand(If(kostenrahmen <= 10, "Beton", "Stein"))
End Sub
End Class
Module Vererbung
Sub Test()
Dim bude As IHaus = New Bude() : bude.Wand(15)
Dim villa As IHaus = New Villa() : villa.Wand(15)
Console.ReadLine()
End Sub
End Module
End Namespace
Der erste Aufruf von Wand() nutzt die Implementation der Klasse Haus. Die zweite Ausgabe zeigt, dass die neue Implementation von Villa verwendet wird.
Materialwahl Haus : Wanddicke Haus 20
Materialwahl Villa: Wanddicke Haus 25
Hinweis |
Ist eine Schnittstelle implementiert, dürfen alle Kindklassen mit Implements diese Tatsache erneut deklarieren. Dabei kann ein Teil oder die ganze Schnittstelle neu implementiert werden. |
Basistyp
Die Aussage, dass alle Klassen als Wurzel die Klasse Object haben, erstreckt sich nicht auf Schnittstellen. Das nächste Codefragment testet auf den Elterntyp einer Schnittstelle:
'...\Klassendesign\Schnittstellen\Wurzel.vb |
Option Strict On
Namespace Klassendesign
Interface IWurzel : End Interface
Module Wurzel
Sub Test()
If GetType(IWurzel).BaseType Is Nothing Then _
Console.WriteLine("Object ist nicht Basis!")
Console.ReadLine()
End Sub
End Module
End Namespace
Wie die Ausgabe zeigt, hat die Schnittstelle nicht Object als Basis:
Object ist nicht Basis!
Trotzdem können Schnittstellenreferenzen auf Mitglieder der Klasse Object zugreifen und Erweiterungsmethoden vom Typ Object nutzen (siehe Abschnitt 4.8.4, »Klassenerweiterungen: Extension«), da eine implizite Konvertierung existiert. Dazu zeigt das nächste Beispiel den Zugriff auf GetType() der Klasse Object:
'...\Klassendesign\Schnittstellen\Object.vb |
Option Strict On
Namespace Klassendesign
Interface IObject : End Interface
Class Objekt : Implements IObject : End Class
Module KonvertierungZuObject
Sub Test()
Dim ref As IObject = New Objekt()
Console.WriteLine("Typ: {0}", ref.GetType().Name)
Console.ReadLine()
End Sub
End Module
End Namespace
Der korrekte Typ wird ausgegeben:
Typ: Objekt
3.15.3 Schnittstellenvererbung 

Neben Klassen können auch Schnittstellen voneinander erben. Im Gegensatz zu Klassen gilt:
Eine Schnittstelle darf mehrere Elternschnittstellen haben, aber keine Elternklasse. |
Dabei werden alle Mitglieder aller Elternklassen übernommen, sodass bei der Implementation der Kindschnittstelle auch alle Mitglieder aller Elternklassen berücksichtigt werden müssen. Sonst wäre ja die Kindschnittstelle nicht vollständig implementiert. Im folgenden Beispiel erbt die Schnittstelle IZitrusfrucht von den Schnittstellen IObst und ILebensmittel. Die Klasse Orange deklariert Implements IZitrusfrucht und muss daher alle drei Methoden der Schnittstelle implementieren, wobei die Methoden Vitamine() und Kalorien() über Vererbung in die Schnittstelle gelangt sind.
'...\Klassendesign\Schnittstellen\Schnittstellenvererbung.vb |
Option Strict On
Namespace Klassendesign
Interface IObst
Sub Vitamine()
End Interface
Interface ILebensmittel
Sub Kalorien()
End Interface
Interface IZitrusfrucht : Inherits IObst, ILebensmittel
Sub Schälen()
End Interface
Class Orange : Implements IZitrusfrucht
Sub Vitamine() Implements IObst.Vitamine
Console.WriteLine("Orange hat Vitamin C.")
End Sub
Sub Schälen() Implements IZitrusfrucht.Schälen
Console.WriteLine("Orange wird geschält mit einem Messer.")
End Sub
Sub Kalorien() Implements ILebensmittel.Kalorien
Console.WriteLine("Orange hat weniger Kalorien als Schokolade.")
End Sub
End Class
Module Schnittstellenvererbung
Sub Test()
Dim orange As IZitrusfrucht = New Orange()
orange.Vitamine() : orange.Kalorien() : orange.Schälen()
Console.ReadLine()
End Sub
End Module
End Namespace
Über die Schnittstellenreferenz sind alle drei implementierten Methoden erreichbar:
Orange hat Vitamin C.
Orange hat weniger Kalorien als Schokolade.
Orange wird geschält mit einem Messer.
Hinweis |
Wie in Abschnitt 3.13.2, »Sichtbarkeitsmodifikatoren«, beschrieben wird, darf eine Kindschnittstelle nicht sichtbarer sein als ihre Eltern. |
Mehrfachvererbung
Bei der Vererbung von Schnittstellen werden nur Signaturen vererbt. Wird nun durch Mehrfachvererbung auf verschiedenen Wegen dieselbe Signatur vererbt, ist sie immer noch identisch dieselbe und findet sich in der Kindschnittstelle auch nur einmalig wieder. Das folgende Beispiel stellt die Methode Schneiden() in ITaschenmesser durch Vererbung sowohl über IMesser als auch über ISäge zur Verfügung. Dennoch reicht es, in der Klasse Taschenmesser die Methode nur einmalig zu implementieren. Statt Implements ITaschenmesser.Schneiden darf daher auch Implements IMesser.Schneiden oder Implements ISäge.Schneiden verwendet werden. Da alle drei Möglichkeiten dieselbe Methode implementieren, darf auch nur eine der drei vorkommen.
'...\Klassendesign\Schnittstellen\Mehrfachvererbung.vb |
Option Strict On
Namespace Klassendesign
Interface ISchnittwerkzeug : Sub Schneiden() : End Interface
Interface IMesser : Inherits ISchnittwerkzeug : End Interface
Interface ISäge : Inherits ISchnittwerkzeug : End Interface
Interface ITaschenmesser : Inherits IMesser, ISäge : End Interface
Class Taschenmesser : Implements ITaschenmesser
Sub Schneiden() Implements ITaschenmesser.Schneiden
Console.WriteLine("Mit Taschenmesser Schneiden")
End Sub
End Class
Module Mehrfachvererbung
Sub Test()
Dim taschenmesser As ITaschenmesser = New Taschenmesser()
taschenmesser.Schneiden()
Console.ReadLine()
End Sub
End Module
End Namespace
Wenn eine Schnittstelle mehrere Elternschnittstellen haben kann, tauchen Probleme auf, die bei der Einfachvererbung der Klassen nicht auftreten können. Wenn eine Schnittstelle identische Signaturen aus verschiedenen Elternschnittstellen übernimmt, so hat sie zwei (mehrdeutige) Mitglieder, die gleich lauten. Beim Zugriff würde ein Konflikt entstehen, da nicht entschieden werden kann, welche denn nun gemeint ist. Daher muss über die passende Basisschnittstellenreferenz zugegriffen werden. Das folgende Codefragment definiert eine Schnittstelle IStereoanlage, die sowohl von IRadio als auch von ICompactDisc die Methodensignatur Musik() erbt. Die Klasse Musikanlage implementiert die gleichlautenden Signaturen in verschiedenen Methoden. In der Realität ist der Begriff von Musik ja schließlich auch recht unterschiedlich. In der Methode Test() kommt es nun zum Zugriff auf die Methode Musik() über die mehrdeutige Schnittstellenreferenz. Der direkte Zugriffsversuch wird vom Compiler zurückgewiesen und ist daher auskommentiert. Erst durch eine Typumwandlung, die eindeutig klarmacht, auf welche Methode zugegriffen werden soll, können die beiden Methoden verwendet werden.
'...\Klassendesign\Schnittstellen\Mehrdeutig.vb |
Option Strict On
Namespace Klassendesign
Interface IRadio : Sub Musik() : End Interface
Interface ICompactDisc : Sub Musik() : End Interface
Interface IStereoanlage : Inherits IRadio, ICompactDisc : End Interface
Class Musikanlage : Implements IStereoanlage
Sub Hifi() Implements ICompactDisc.Musik
Console.WriteLine("'s Brent, briderlech, 's brent ...")
End Sub
Sub Schepper() Implements IRadio.Musik
Console.WriteLine("All we like sheep ...")
End Sub
End Class
Module Mehrdeutig
Sub Test()
Dim anlage As IStereoanlage = New Musikanlage()
'anlage.Musik() 'Compilerfehler: mehrdeutig!!
CType(anlage, IRadio).Musik()
CType(anlage, ICompactDisc).Musik()
Console.ReadLine()
End Sub
End Module
End Namespace
Die verschiedenen Arten der Musik machen sich in der Ausgabe bemerkbar:
All we like sheep ...
's Brent, briderlech, 's brent ...
3.15.4 Schnittstelle oder abstrakte Klasse? 

Die Konzepte einer Schnittstelle und abstrakten Klasse sind sehr ähnlich. Es gibt keine allgemeine Empfehlung, wann welche benutzt werden sollte. Die Tabelle 3.27 soll eine Hilfestellung für die Entscheidung sein. Ist keine eindeutige Entscheidung möglich, wählen Sie eine Möglichkeit und experimentieren damit. In der Programmierpraxis werden Sie dann »Ihren« Weg finden.
Art | Schnittstelle | abstrakte Klasse |
Vererbung |
mehrfach |
einfach |
Implementation |
nie, reiner Vertrag |
darf (oft allgemeine Funktionalität) |
Abstraktion |
vollständig |
von gar nicht bis vollständig |
Änderungen nach Freigabe |
unbedingt vermeiden |
Signaturen und Rückgabetypen unbedingt unverändert, im implementierten Teil kann notfalls geändert werden. |
typisches Einsatzgebiet |
Toolklassen, zum Beispiel zum Sortieren und Selektieren |
an sich konkrete Klassen, in denen ein Teil erst in Kindklassen festgelegt wird, zum Beispiel Drucker mit allgemeiner Warteschlange |
3.15.5 Grafikbibliothek: Flächen 

In diesem Abschnitt erweitern wir die in Abschnitt 3.1.12, »Grafikbibliothek: Beispiel für Kapitel 3 und 4«, eingeführte und zuletzt in Abschnitt 3.14.7, »Grafikbibliothek: Objektsammlungen«, erweiterte Grafikanwendung. Dazu werden zwei Schnittstellen eingeführt, die den Namen und den Umfang eines Umrisses beschreiben:
'...\Klassendesign\Graphik\Schnittstellen.vb |
Option Explicit On
Namespace Klassendesign
Public Interface IFigur
Function Name() As String
End Interface
Public Interface IUmriss : Inherits IFigur
ReadOnly Property Umfang() As Double
End Interface
...
End Namespace
Im Rechteck werden die Schnittstellen implementiert. Der Name soll polymorph sein und wird mit Overridable gekennzeichnet sowie im Quadrat überschrieben.
'...\Klassendesign\Graphik\Schnittstellen.vb |
Option Explicit On
Namespace Klassendesign
...
Partial Public Class Rechteck : Inherits Vieleck : Implements IUmriss
Public Overridable Function Name() As String Implements IFigur.Name
Return "Rechteck"
End Function
Public ReadOnly Property Umfang() As Double Implements IUmriss.Umfang
Get
Return 2 * a + 2 * b
End Get
End Property
End Class
Partial Public NotInheritable Class Quadrat : Inherits Rechteck
Public Overrides Function Name() As String
Return "Quadrat"
End Function
End Class
End Namespace
Zum Test werden ein paar Umrisse erzeugt und über den Schnittstellentyp angesprochen:
'...\Klassendesign\Zeichner\Scnittstellen.vb |
Option Explicit On
Namespace Klassendesign
Partial Class Zeichner
Sub Schnittstellen()
Dim umrisse() As IUmriss = {New Quadrat(7), New Rechteck(4, 6)}
For Each u As IUmriss In umrisse
Console.WriteLine(u.Name() & " mit " & u.Umfang & " Umfang")
Next
End Sub
End Class
End Namespace
Zur Kontrolle sehen Sie hier die Ausgabe der Methode Schnittstellen():
Quadrat mit 28 Umfang
Rechteck mit 20 Umfang
Die nächste Erweiterung erfolgt in Abschnitt 3.2.6, »Grafikbibliothek: private Größe des Rechtecks«.
Ihre Meinung
Wie hat Ihnen das Openbook gefallen? Wir freuen uns immer über Ihre Rückmeldung. Schreiben Sie uns gerne Ihr Feedback als E-Mail an kommunikation@rheinwerk-verlag.de.