Klassen und Objekte

Werbung
Lerneinheit 1: Klassen und Objekte
Wir beschäftigen uns mit
● der Erstellung gekapselter Klassen sowie der Instanzierung von Objekten,
● Methoden, Eigenschaften, Zugriffsmethoden und Konstruktoren,
● der Nutzung von Vererbung und Polymorphie,
● dem Zugriff auf XML-Dateien und Datenbanken sowie
● der Verwendung generischer Listen und Funktionszeiger.
Lerneinheit 2: Vererbung
ro
Lerneinheit 1: Klassen und Objekte
54
54
57
59
61
63
67
69
71
71
Lernen . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1 Subklassen . . . . . . . . . . . . . . . . . . . . . . .
2 Konstruktoren in Subklassen . . . . . . . . .
3 Methoden überschreiben . . . . . . . . . . . .
4 Polymorphie . . . . . . . . . . . . . . . . . . . . . .
5 Abstrakte und versiegelte Klassen . . . . .
6 Interfaces . . . . . . . . . . . . . . . . . . . . . . . . .
Üben . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Sichern . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Wissen . . . . . . . . . . . . . . . . . . . . . . . . . . . . sep
Lernen . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 Klasse erstellen . . . . . . . . . . . . . . . . . . . .
2 Eigenschaften und Methoden . . . . . . .
3 Kapselung . . . . . . . . . . . . . . . . . . . . . . .
4 Zugriffsmethoden . . . . . . . . . . . . . . . . .
5 Konstruktor und Destruktor . . . . . . . . . .
6 Statische Elemente . . . . . . . . . . . . . . . . .
Üben . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Sichern . . . . . . . . . . . . . . . . . . . . . . . . . . . Wissen . . . . . . . . . . . . . . . . . . . . . . . . . . . . Lerneinheit 3: Weitere OOP-Konzepte
Le
Lernen . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1 Generics . . . . . . . . . . . . . . . . . . . . . . . . . .
2 Innere Klassen . . . . . . . . . . . . . . . . . . . . .
3 Indexer . . . . . . . . . . . . . . . . . . . . . . . . . . .
4 Delegates und Events . . . . . . . . . . . . . . .
Üben . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Sichern . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Wissen . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
73
76
78
79
81
83
85
87
87
Lerneinheit 4: Datenspeicherung
89
89
92
93
95
97
98
99
Lernen . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1 Drei-Schichten-Architektur . . . . . . . . . .
2 Textdateien . . . . . . . . . . . . . . . . . . . . . .
3 Dateisystem-Operationen . . . . . . . . . . .
4 XML-Serialisierung . . . . . . . . . . . . . . . .
5 Datenbankzugriff mit ADO.NET . . . . .
6 DataGridView-Control . . . . . . . . . . . . .
Üben . . . . . . . . . . . . . . . . . . . . . . . . . . . . Sichern . . . . . . . . . . . . . . . . . . . . . . . . . . .
Wissen . . . . . . . . . . . . . . . . . . . . . . . . . . . 100
100
101
104
106
110
117
119
120
120
Kapitelrückblick . . . . . . . . . . . . . . . . . . . . 122
Ich bin Ms. Check! Ich kenne
mich sehr gut aus und habe
auf jede Frage eine verständliche Antwort.
Ich bin Mr. What! Ich
kenne mich ganz gut
aus, habe aber immer
wieder einige Zwischenfragen …
Softwareentwicklung
53
Objektorientiertes Programmieren
Programmieren
22 Objektorientiertes
In diesem Kapitel erarbeiten wir die Konzepte der objektorientierten Programmierung, wie gekapselte Klassen, Instanzierung von Objekten und Verwendung von Vererbung und Polymorphie, anhand der Programmiersprache C#.NET.
be
2
Objektorientiertes Programmieren
Lernen
Üben
Sichern
Wissen
Lerneinheit 1
Klassen und Objekte
Alle SbX-Inhalte zu dieser Lerneinheit findest
du unter der ID: 1178.
In dieser Lerneinheit lernen wir die wichtigsten Basiskonzepte objektorientierter
Programmierung, wie z.B. Klassen und Objekte sowie deren Eigenschaften und Methoden, kennen. Wir beschäftigen uns mit dem Grundprinzip der Kapselung sowie
deren Auswirkung auf Klassen und Objekte. Außerdem sehen wir uns an, wie die
Kapselung anhand von Zugriffsmethoden realisiert wird.
In einem immer komplexer werdenden Lehrbeispiel beschäftigen wir uns mit
1 Klasse erstellen
Das Objekt-Datenmodell
ro
Lernen
be
● der Erstellung von Klassen und der Instanzierung von Objekten,
● gekapselten Eigenschaften, Methoden und Zugriffsmethoden,
● Konstruktoren, Destruktoren sowie dem Überladen von Methoden und
● mit der Verwendung statischer Elemente.
sep
Wie könnten wir einem Außerirdischen erklären, was wir unter einem Auto verstehen? Natürlich
wissen wir alle, was ein Auto ist. Aber wie können wir ein Auto ganz allgemein beschreiben? Es
hat z.B. meist vier Räder, aber auch ein Auto mit sechs Rädern wäre vorstellbar. Es hat ein Lenkrad, aber auch ein Fahrschulauto mit zwei Lenkrädern wäre denkbar. Es hat einen Motor, aber
auch ein Modellauto ohne Motor ist ein Auto. Also, was ist nun eigentlich ein Auto?
Ü 1:
Beschreibe generelle Merkmale für jedes auf der Welt existierende Auto.
Le
Wie wir gesehen haben, ist es kaum möglich, für Objekte der Wirklichkeit allgemeingültige,
konkrete Eigenschaften zu nennen. Nicht jedes Auto hat vier Räder, nicht jedes Auto hat nur
ein Lenkrad. Aber – jedes Auto hat Räder und mindestens ein Lenkrad! Wie viele Räder und
Lenkräder es hat, kann im Allgemeinen nicht festgelegt werden.
Zugegeben – diese Art der Darstellung ist sehr abstrakt, aber für jedes Auto gültig.
Klasse und Objekt
Eine Klasse
beschreibt generelle
Merkmale und
Funktionen.
Ein Objekt
ist eine konkrete Ausprägung einer Klasse.
1 Eine Klasse beschreibt allgemeine, abstrakte Merkmale, die für alle der Klasse zugehörigen Objekte gültig sind.
Die Klasse Auto weist z.B. folgende Merkmale auf: Räder, Lenkrad, Türen, Sitze, Fahren, Tanken. Jedes Auto muss Maut bezahlen, wenn es die Autobahn benutzt.
2 Ein Objekt ist eine konkrete Ausprägung einer Klasse.
Ein Objekt der Klasse Auto wäre z.B. der blaue BMW 320d von Julia Kern mit dem amtlichen Kennzeichen S-JULY1, einem Kilometerstand von 67.845 km und einem aktuellen Tankinhalt von 23,7 Litern Diesel.
Die folgende Grafik veranschaulicht den Zusammenhang zwischen Klasse und Objekt.
54
Softwareentwicklung
Lerneinheit 1: Klassen und Objekte
Klasse Auto
2 Objektorientiertes Programmieren
Objekt Mercedes
Objekt Porsche
be
Objekt BMW
Objekt Audi
Objekte sind Instanzen einer Klasse.
Abb.: Klasse und Objekt
ro
Diese Abbildung findest
du in der PowerPointPräsentation unter der
ID: 1179.
Vererbung
Eine Klasse wie z.B. Auto kann aus weiteren Klassen, sogenannten Subklassen, bestehen. So
könnte es beispielsweise eine Klasse PKW und eine Klasse LKW geben. Die Klasse PKW könnte
wiederum in eine Klasse Benzin und eine Klasse Diesel unterteilt werden.
Die Subklasse
ist die untergeordnete
Klasse, die von der
Basisklasse erbt.
Vererbung ist ein Grundprinzip objektorientierter Programmierung. Dabei erbt eine Subklasse
alle Merkmale und Funktionen einer übergeordneten Klasse, der Basisklasse. Mit der Anwendung der Vererbung beschäftigen wir uns in der nächsten Lerneinheit in diesem Kapitel.
sep
Die Basisklasse
ist die übergeordnete
Klasse.
L 1:
Welche Merkmale und Funktionen enthalten die Klassen Auto, PKW und LKW?
Mr. What und
Ms. Check
Le
Auto: Kennzeichen, Marke, Verbrauch, Tankinhalt, Kraftstoffvorrat, Fahren, Tanken
PKW: alle Merkmale von Auto + Transportkapazität, Sitzplatzanzahl
LKW: alle Merkmale von Auto + Transportkapazität, Achszahl
Welche Merkmale und Funktionen hat die Klasse Schüler?
Bin ich eine Klasse oder ein Objekt?
Vorname, Zuname, Klasse, Katalognummer, Erziehungsberechtigte, Fächer, Lernen, Prüfung, Noten usw.
Du bist ein Objekt, da du konkrete Merkmale und Funktionen aufweist.
Ü 2:
Handelt es sich bei den folgenden Aussagen um Angaben zu einer Klasse oder einem
Objekt?
1. Ein Auto hat ein Reserverad.
2. Ein PKW mit Anhänger darf auf dem Firmenparkplatz nicht parken.
3. Ein Auto ist blau.
4. Ein PKW kann Personen befördern.
5. Ein Auto hat eine Klimaanlage.
Softwareentwicklung
55
Lernen
Üben
Sichern
Wissen
Objekte aus einer Klasse instanzieren
Im Rahmen der objektorientierten Programmierung verwenden wir Klassen, in denen Eigenschaften und Operationen (Methoden) festgelegt werden. Bei der Erzeugung eines Objektes
wird der Inhalt einer Klasse auf das Objekt übertragen, ein Objekt wird daher auch als Instanz
einer Klasse bezeichnet.
Klasse Auto
Datentyp
Objekt audi
Konstruktor
Abb.: Objekt aus einer Klasse instanzieren
Instanzierung
Konstruktormethode
sep
Diese Abbildung findest
du in der PowerPointPräsentation unter der
ID: 1179.
ro
Jede Klasse erhält automatisch eine StandardKonstruktormethode
ohne Parameter,
z.B. Auto().
Objektvariable
be
Der Konstruktor new
ruft die Konstruktormethode Auto() auf, die
das Objekt erzeugt.
1 Ein Objekt wird in einer Objektvariablen mit dem Datentyp der Klasse gespeichert.
Objektvariablen:
Auto audi;
Auto bmw;
Objekte erzeugen:
audi = new Auto();
bmw = new Auto();
Hinweis
Die Deklaration der Objektvariablen mittels Auto audi erzeugt die Variable audi vom Datentyp der angegebenen Klasse Auto. Bei diesem Vorgang wird noch kein Objekt instanziert!
Der Inhalt der Objektvariablen audi ist zu diesem Zeitpunkt null.
2 Ein Objekt wird durch den Aufruf eines Konstruktors mit einer entsprechenden
Konstruktormethode instanziert.
Le
null = kein Wert
Die Initialisierung der Objektvariablen audi mit new Auto() erzeugt ein neues Objekt, indem
die Konstruktormethode Auto() aus der Klasse Auto aufgerufen wird.
Jede Klasse hat eine Standard-Konstruktormethode, die ein neues Objekt aus der Klasse
erzeugt. Der Name dieses Standardkonstruktors ist der Klassenname, z.B. Auto().
L 2: Klasse mit Objekten
Erstelle die Klasse Auto mit den Eigenschaften Kennzeichen und Marke vom Typ String
und erzeuge die Objekte Audi und BMW.
class Auto // Deklaration der Klasse Auto
{
string kennzeichen, marke; // Deklaration der Eigenschaften
}
Die Variablen audi und
bmw sind vom Typ der
Klasse Auto und beinhalten die Objekte.
56
Auto audi = new Auto(); // Objekt Audi aus Auto instanzieren
Auto bmw = new Auto(); // Objekt BMW aus Auto instanzieren
Softwareentwicklung
Lerneinheit 1: Klassen und Objekte
2 Eigenschaften und Methoden
Inhalte von Klassen und Objekten
Wir haben gesehen, dass eine Klasse abstrakte Inhalte hat, während ein Objekt über sehr konkrete Inhalte verfügt. Doch welche Inhalte können das sein?
besteht
aus
2 Objektorientiertes Programmieren
Sehen wir uns anhand der folgenden Abbildung die Inhalte der Klasse Auto genauer an:
besteht
aus
Klasse Auto
Methoden
be
Eigenschaften
Marke
Fahren()
Kennzeichen
Verbrauch
Tanken()
Kraftstoffvorrat
Diese Abbildung findest
du in der PowerPointPräsentation unter der
ID: 1179.
Fahrtkosten
ro
Tankinhalt
Abb.: Eigenschaften und Methoden der Klasse Auto
Eigenschaften
der Klasse
Marke
Kennzeichen
Eigenschaften
Objekt 1
Eigenschaften
Objekt 2
Eigenschaften
Objekt 3
Audi A6
BMW 525d
Porsche 911
W-702AB
KS-545AM
S-911C
8,9 l/100 km
7,5 l/100 km
16,2 l/100 km
Tankinhalt
80 l
75 l
70 l
Kraftstoffvorrat
45,6 l
12,9 l
58,4 l
Fahrtkosten
195,80 EUR
157,50 EUR
356,40 EUR
Le
Verbrauch
sep
Die Klasse Auto beschreibt Eigenschaften und Methoden für alle Autos. Jedes Auto-Objekt
besitzt die gleichen Eigenschaften und Methoden wie die gesamte Klasse. Aber jedes Objekt
kann für eine Eigenschaft einen eigenen konkreten Wert enthalten. So könnte es in einem
Programm beispielsweise folgende Auto-Objekte geben:
Eigenschaften und Methoden
Eigenschaften
sind Variablen
einer Klasse.
Methoden
sind Prozeduren bzw.
Funktionen einer
Klasse.
1 Eine Eigenschaft beschreibt den Zustand eines Objekts.
Jedes Auto-Objekt aus der Klasse Auto hat einen Verbrauch und einen Benzinvorrat. Die
Eigenschaften verändern sich, wenn ein Auto fährt oder aufgetankt wird.
2 Eine Methode beschreibt das Verhalten eines Objekts.
Die Methode Fahren() erhöht für jedes Auto-Objekt die Eigenschaften Fahrtkosten und
vermindert den Kraftstoffvorrat. Die Methode Tanken() erhöht den Kraftstoffvorrat.
Eigenschaften können durch Methoden beeinflusst und verändert werden. Die Methode
Tanken() hat z.B. die Aufgabe, den Kraftstoffvorrat zu erhöhen. Jedes Objekt ist in der Lage,
seine eigenen Eigenschaften zu speichern und durch seine Methoden zu verändern. Die Eigenschaften von Objekten können jederzeit abgefragt werden.
Softwareentwicklung
57
Lernen
Üben
Sichern
Wissen
Ü 3:
Bei welchen dieser Inhalte handelt es sich um Eigenschaften, bei welchen um Methoden?
1. Tanken
2. Tankinhalt
3. Maut entrichten
4. Anzahl der Sitzplätze
5. Durchschnittlicher Kraftstoffverbrauch
6. Serviceintervall
7. Service durchführen
8. Farbe
Ist die Farbe Rot eines VW-Käfers die Eigenschaft einer Klasse oder eines Objekts?
Für die Klasse Schüler wären z.B. folgende Methoden
denkbar: Lernen(), Prüfung(), Zeugnis(), Aufsteigen(),
Wiederholen(), Schulabschluss() usw.
ro
Welche Methoden könnte
es bei einer Klasse Schüler
geben?
Eine Eigenschaft der Klasse Auto ist die Farbe. Rot
ist eine konkrete Farbe und gehört daher zu einem
bestimmten Auto-Objekt.
be
Mr. What und
Ms. Check
Wir haben nun die wichtigsten Bestandteile einer Klasse kennengelernt. Im Rahmen eines immer
komplexer werdenden Lehrbeispiels wenden wir unsere Kenntnisse an.
sep
Das Lehrbeispiel „Frachtkostenoptimierung“
Le
In diesem Kapitel erstellen wir Schritt für Schritt eine Anwendung in der Programmiersprache
C#. In dieser Lerneinheit beginnen wir mit der Klasse Auto sowie der Erstellung von AutoObjekten. Unsere Anwendung soll das günstigste Transportmittel aus einem vorhandenen Fuhrpark ermitteln. Im Fuhrpark gibt es Autos mit unterschiedlichen Transportkapazitäten und Kosten pro gefahrenem Kilometer. Nachdem der Anwender das Transportgewicht sowie die Fahrtstrecke eingegeben hat, soll das Programm die Kosten für jedes Auto berechnen und jenes mit
den geringsten Gesamtkosten ermitteln.
L 3: Klasse
Wir beginnen in Visual Studio 2005 eine neue C#-Windows-Anwendung und erstellen eine
neue Klasse mit dem Namen „Auto“.
namespace cs_Frachtkostenoptimierung
{
class Auto
{
// Eigenschaften
string kennzeichen, marke;
double verbrauch, tankinhalt, kraftstoffvorrat, fahrtkosten;
Beim Tanken wird der
Kraftstoffvorrat um
die getankte Menge
erhöht.
58
// Methode Tanken
void Tanken(double liter)
{
kraftstoffvorrat += liter;
}
}
}
Softwareentwicklung
Lerneinheit 1: Klassen und Objekte
Das wichtigste Grundprinzip objektorientierter Programmierung ist die Eigenständigkeit der
Klassen bzw. Objekte. Ein Objekt darf nur gültige Werte in seinen Eigenschaften speichern und
nur dann eine Methode ausführen, wenn dies auch zulässig ist. Über definierte Schnittstellen
kann jeder beliebige Programmierer Klassen und Objekte benutzen. Dieses Prinzip nennt sich
Kapselung.
Objekte sind eigenverantwortlich.
be
Ein wichtiges Ziel objektorientierter Programmierung ist die Modularisierung von Programmkomponenten, damit auch andere Programmierer mit diesen Komponenten arbeiten können. Dazu
ist es notwendig, dass Klassen möglichst selbständig funktionieren und fehlerhafte Aufrufe oder
Daten nicht zulassen. Die Umsetzung dieses Grundsatzes wird als Kapselung bezeichnet.
Kapselung
Kapselung
bedeutet Zusammenfassen von Daten und
Methoden.
bedeutet, dass
1 Methoden für ihre korrekte Funktion selbst verantwortlich sind
und dass
ro
2 Eigenschaften nur durch zulässige Methodenaufrufe verändert werden dürfen.
Eigenschaften sind
private
Diese Grafik findest du
in der PowerPointPräsentation unter der
ID: 1179.
Beachte
Auto
Kein
Zugriff
Zugriff
kraftstoffvorrat
fahrtkosten
Fahren(km)
Tanken(liter)
Ein direkter Zugriff auf Eigenschaften
von außen würde die Kontrollfunktion
der Methoden unterlaufen. Aus diesem
Grund dürfen Eigenschaften nicht von
außen veränderbar sein. Sie sind in der
Klasse eingekapselt und können nur
mit Hilfe von Methoden (Zugriffsmethoden) gelesen oder verändert werden.
Le
Methoden sind
public
sep
Die Fahrtkosten dürfen nur durch das Fahren des Autos verändert werden. Außerdem dürfen
sich die Fahrtkosten nur erhöhen und niemals verringern, z.B. wenn ein Auto rückwärts fährt.
Gleichzeitig vermindert die Mehode Fahren() den Kraftstoffvorrat. Die Kontrolle darüber hat
die Methode Fahren(). Das Tanken bewirkt die Erhöhung des Kraftstoffvorrates. Die Methode Tanken() muss prüfen, dass der Tank nicht überläuft.
Abb.: Kapselung der Klasse Auto
Eigenschaften dürfen von außen nur mittels Methoden gelesen oder verändert werden.
Daher sind Eigenschaften innerhalb einer Klasse gekapselt und niemals als public deklariert.
Aus dem Prinzip der Kapselung ergibt sich zwangsläufig, dass nur über genau festgelegte
Schnittstellen, nämlich die Methoden, auf eine Klasse bzw. ein Objekt zugegriffen werden kann.
Würde ein Programmierer Eigenschaften von außen zugänglich machen, so könnten diese Eigenschaften ohne die Kontrolle der Methoden verändert werden. In unserem Beispiel wäre es
dann z.B. denkbar, die Transportkosten eines Auto-Objektes auf betrügerische Art und Weise zu
ändern, um einem bestimmten Auto den Vorzug zu geben.
Softwareentwicklung
59
2 Objektorientiertes Programmieren
3 Kapselung
Lernen
Üben
Sichern
Wissen
Grundsätze der Kapselung
private Eigenschaft:
ist nur ihrer Klasse
bekannt
protected Eigenschaft:
ist der Klasse und ihren
Subklassen bekannt
1 Eigenschaften sind nur Objekten der eigenen Klasse (private) oder einer Subklasse (protected) bekannt.
Die Eigenschaft Verbrauch ist für die Klasse Auto und für jedes Auto-Objekt eine als private festgelegte Variable. Wenn Verbrauch auch bei der Klasse LKW, die alle Eigenschaften
von Auto erbt, bekannt ist, wird die Variable als protected deklariert.
2 Eigenschaften dürfen nur durch Methoden verändert werden.
Die Eigenschaft Kraftstoffvorrat darf nur durch die Methode Tanken() erhöht werden.
Eine Reduzierung des Kraftstoffvorrates ist nur durch die Methode Fahren() möglich.
be
3 Methoden bedienen sich der Eigenschaften einer Klasse. Öffentliche Methoden
dienen als Schnittstelle der Klassen. Private Methoden dienen innerhalb der Klasse
als Hilfsmethoden.
Die öffentliche Methode Fahren() reduziert z.B. die Eigenschaft Kraftstoffvorrat um den
verbrauchten Kraftstoff, egal ob das Auto vorwärts oder rückwärts fährt.
Welchen Vorteil haben Kapseln bei Veränderungen von Objekteigenschaften?
Kapseln kontrollieren vor einer Veränderung,
ob diese zulässig ist.
Klassen können als Komponenten auch von anderen Entwicklern
verwendet werden, bieten genau definierte Schnittstellen nach
außen und sorgen selbst für ihre korrekte Verwendung.
sep
Welchen Vorteil haben Kapseln
bei der objektorientierten Programmierung?
ro
Mr. What und
Ms. Check
L 4: Kapselung
Die Klasse Auto soll dem Prinzip der Kapselung entsprechen. Eigenschaften dürfen von
außen nicht direkt beeinflusst werden, sondern werden über die Methoden verändert.
Methoden sind public,
da sie von außerhalb
der Klasse bzw. des
Objektes aufgerufen
werden.
Die Methoden sorgen
für gültige Werte in den
Eigenschaften.
60
Le
Eigenschaften dürfen
nicht public sein.
namespace cs_Frachtkostenoptimierung
{
class Auto
{
// Eigenschaften
private string kennzeichen, marke;
private double verbrauch, tankinhalt,
kraftstoffvorrat, fahrtkosten;
// Methode Tanken
public void Tanken(double liter)
{
if (kraftstoffvorrat + liter > tankinhalt)
throw new
Exception("So viel passt nicht in den Tank.");
else
kraftstoffvorrat += liter;
}
}
}
Softwareentwicklung
Lerneinheit 1: Klassen und Objekte
Wir haben gelernt, dass wir Klassen kapseln müssen und Eigenschaften niemals von außen
zugänglich machen dürfen. Um dennoch mit Eigenschaften effizient arbeiten zu können, benötigen wir Zugriffsmethoden als Schnittstelle nach außen. Nun besprechen wir, welche Zugriffsmethoden es gibt und welche Aufgaben sie erfüllen.
4 Zugriffsmethoden
Beachte
Die Kapselung bewirkt, dass Eigenschaften nur noch der Klasse bzw. dem aus der Klasse erzeugten Objekt bekannt sind. Für jeden Zugriff auf eine Eigenschaft benötigen wir daher eine
Methode – eine Zugriffsmethode.
be
Property
bedeutet
Zugriffsmethode.
Eine Methode, deren Aufgabe darin besteht, eine Eigenschaft zu lesen (Get-Property)
oder zu verändern (Set-Property), nennt man eine Zugriffsmethode.
Eine Zugriffsmethode
kann entweder nur ein
Get-, nur ein Set- oder
ein Get- und ein SetProperty implementieren.
ro
Ein Auto-Objekt hat die Eigenschaften Kraftstoffvorrat und Fahrtkosten sowie die Methoden
Fahren() und Tanken(), welche diese beiden Eigenschaften verändern. Beim Fahren werden die
Fahrtkosten erhöht und der Kraftstoffvorrat verringert. Beim Tanken wird der Kraftstoffvorrat
erhöht.
Über Zugriffsmethoden können wir die berechneten Fahrtkosten und den Kraftstoffvorrat
eines Auto-Objekts abfragen. Ein Get-Property dient zum Lesen einer Eigenschaft. Die Veränderung einer Eigenschaft erfolgt mittels Set-Property.
sep
Auto
kraftstoffvorrat
fahrtkosten
In C# haben
Eigenschaften einen
kleinen und Properties
einen großen Anfangsbuchstaben.
Methode
Zugriff
von außen
Diese Abbildung findest
du in der PowerPointPräsentation unter der
ID: 1179.
Fahrtkosten
Kraftstoffvorrat
Le
Property
Fahren()
Tanken()
Abb.: Zugriffsmethoden (Properties) für Kraftstoffvorrat und Fahrtkosten
Anwendung von Properties
1 Ein Property ist eine Methode zum Lesen oder Schreiben von Eigenschaften. Es
ist immer public und dient als Schnittstelle für eine Eigenschaft.
Das Property Fahrtkosten ist als public deklariert. Es liest die private Eigenschaft
Fahrtkosten und liefert das Ergebnis nach außen.
Ein Get-Property
dient zum Lesen von
Eigenschaften.
Ein Set-Property
dient dem Setzen von
Eigenschaften.
Softwareentwicklung
2 Get-Properties ermöglichen das Lesen von Eigenschaften.
Die Eigenschaften Fahrtkosten und Kraftstoffvorrat haben Get-Properties.
3 Set-Properties ermöglichen das Ändern von Eigenschaften.
Anstelle der Methode Tanken() könnte auch die Eigenschaft Kraftstoffvorrat ein Set-Property haben. Von dieser Methode müsste dann geprüft werden, ob eine gültige Kraftstoffmenge getankt wird und dieser neue Kraftstoffvorrat auch wirklich in den Tank passt.
61
2 Objektorientiertes Programmieren
„Property“ ist nicht gleich „Eigenschaft“.
Lernen
Üben
Mr. What und
Ms. Check
Sichern
Wissen
Was unterscheidet ein Property
von einer Eigenschaft?
Eigenschaften sind nur der Klasse bekannt. Ein Property ermöglicht den Zugriff auf eine Eigenschaft von außen.
Worin unterscheiden sich Properties
von anderen Methoden?
Properties haben die Funktion, eine bestimmte Eigenschaft zu lesen oder zu ändern. Eine Methode ist in der
Lage, mehrere Eigenschaften gleichzeitig zu ändern.
Was sind Get- und Set-Properties? Muss es
immer beide für eine Eigenschaft geben?
Ein Get-Property liest und ein Set-Property verändert
eine Eigenschaft. Je nach Situation kann es kein Property, ein Set-, ein Get- oder beide Properties geben.
Warum muss ich überhaupt Properties verwenden? Wäre es nicht
einfacher, die Eigenschaften public zu
deklarieren?
ro
be
Ja, aber dann würden wir die Kontrolle über die Eigenschaften verlieren und jedes Programm könnte Objekteigenschaften beliebig verändern. Da der Grundsatz der
Kapselung genau dies vermeiden soll, sind Properties eine sinnvolle Möglichkeit, die Kapselung umzusetzen.
L 5: Properties
Für die Eigenschaften Kraftstoffvorrat und Fahrtkosten der Klasse Auto sollen Zugriffsmethoden (Properties) erstellt werden, die nur das Lesen der Eigenschaften erlauben.
sep
namespace cs_Frachtkostenoptimierung
{
class Auto
{
// Eigenschaften
private string kennzeichen, marke;
private double verbrauch, tankinhalt,
kraftstoffvorrat, fahrtkosten;
Le
// Methode Tanken
public void Tanken(double liter)
{
if (kraftstoffvorrat + liter > tankinhalt)
throw new
Exception("So viel passt nicht in den Tank.");
else
kraftstoffvorrat += liter;
}
Properties
ermöglichen den
Zugriff auf die gekapselten Eigenschaften.
Der Wert der Eigenschaft wird mit return
an das aufrufende Programm zurückgegeben.
62
// Get-Properties
public double Kraftstoffvorrat
{
get { return kraftstoffvorrat; }
}
public double Fahrtkosten
{
get { return fahrtkosten; }
}
}
}
Softwareentwicklung
Lerneinheit 1: Klassen und Objekte
Der übergebene Wert
wird in value
repräsentiert.
be
Auch ein Set-Property
muss die Gültigkeit der
Eigenschaft überprüfen.
// Get- und Set-Property
public double Kraftstoffvorrat
{
get { return kraftstoffvorrat; }
set
{
if (kraftstoffvorrat + value > tankinhalt)
throw new
Exception("So viel passt nicht in den Tank.");
else
kraftstoffvorrat += value;
}
}
ro
Die Aufgabe einer Klasse besteht darin, die erforderlichen Methoden und Eigenschaften für ihre
Objekte festzulegen. Ein Objekt wird aus einer Klasse erzeugt – instanziert. Das Objekt wird als
Instanz einer Klasse bezeichnet. Für die Konstruktion des Objektes gibt es in einer Klasse eine
dafür verantwortliche Methode: den Konstruktor.
5 Konstruktor und Destruktor
Objekte erzeugen und zerstören
Ein Konstruktor ist eine
Methode, die beim
Erzeugen eines neuen
Objektes aufgerufen
wird.
sep
Unsere Klasse Auto besteht nun aus Eigenschaften, Properties und Methoden. Um ein AutoObjekt erzeugen zu können, benötigen wir einen Konstruktor:
Jede Klasse enthält einen Standardkonstruktor – es sei denn, wir schreiben selbst eigene
Konstruktoren. Der Standardkonstruktor hat keine Parameter und keine Implementierung.
Die Konstruktormethode trägt den Namen der Klasse, z.B. Auto().
Es kann viele Konstruktormethoden mit unterschiedlichen Parametern geben. Wir nennen
diese überladene Konstruktormethoden.
Le
Auto objekt =
new Auto();
Konstruktor
Objekt
erzeugen
Konstruktormethode
Diese Abbildung findest
du in der PowerPointPräsentation unter der
ID: 1179.
Der Garbage-Collector
ist die Müllabfuhr in
.NET und entsorgt
nicht mehr benötigte
Objekte, um Ressourcen
und Speicher freizugeben.
Softwareentwicklung
Auto
kraftstoffvorrat
fahrtkosten
Tanken()
Fahren()
Kraftstoffvorrat
Fahrtkosten
Auto()
Abb.: Konstruktormethode Auto()
Die Destruktormethode wird beim Zerstören eines Objektes aufgerufen. Ein Objekt wird
durch den Garbage-Collector verworfen, nachdem wir der Objektvariablen null zugewiesen
haben. Wann der Garbage-Collector den Destruktor aufruft ist nicht vorhersehbar. Die Destruktormethode erhält den Namen der Klasse mit einer voranstehenden Tilde, z.B. ~Auto().
Wie beim Konstruktor gibt es auch beim Destruktor einen Standarddestruktor, der vom
Compiler automatisch generiert wird. Ein Objekt kann auch dann zerstört werden, wenn kein
Destruktor explizit implementiert wurde. Destruktoren können nicht überladen werden.
63
2 Objektorientiertes Programmieren
L 6: Set-Property
Erstelle ein Set-Property zum Tanken und erhöhe mit dem übergebenen Wert die Eigenschaft Kraftstoffvorrat.
Lernen
Üben
Sichern
Wissen
Konstruktormethoden verwenden
1 Eine Konstruktormethode ist für die korrekte Erzeugung eines Objektes zuständig.
Mit einer Konstruktormethode werden die für die Gültigkeit eines Objektes erforderlichen
Eigenschaften, wie z.B. der Verbrauch und die Marke eines Autos, mit Werten initialisiert.
Um ein Auto-Objekt erzeugen zu können, müssen diese Werte als Parameter der Konstruktormethode angegeben werden.
Mr. What und
Ms. Check
Für die Klasse Auto sind folgende Fälle möglich:
be
1. Das zu erzeugende Auto-Objekt ist ein Anhänger. Es gibt demnach keinen Verbrauch.
Diese Aufgabe kann ein Konstruktor ohne Parameter lösen: Auto().
2. Das Auto-Objekt ist ein Neuwagen. Hierzu benötigen wir eine Konstruktormethode, die
den Verbrauch als Parameter erhält: Auto(verbrauch).
3. Das Auto-Objekt ist ein angemeldetes KFZ. Hierzu benötigen wir eine Konstruktormethode, die sowohl den Verbrauch als auch das amtliche Kennzeichen als Parameter
erhält: Auto(verbrauch, kennzeichen).
3 Überladene Konstruktormethoden müssen anhand der Datentypen ihrer Parameter eindeutig unterscheidbar sein.
Die drei oben beschriebenen Konstruktoren unterscheiden sich anhand ihrer Parameter.
Der Standardkonstruktor Auto() enthält keinen Parameter. Er kann den Anhänger erzeugen, da dieser keinen Verbrauch benötigt. Die beiden überladenen Konstruktoren
Auto(verbrauch) und Auto(verbrauch, kennzeichen) erhalten als Parameter den Verbrauch bzw. zusätzlich das Kennzeichen und können voneinander und vom Standardkonstruktor unterschieden werden.
ro
Die Konstruktoren
public Auto(int km) und
public Auto(double
verbrauch) unterscheiden sich z.B. anhand
der Datentypen ihrer
Parameter.
2 Konstruktormethoden können überladen werden.
sep
Das Überladen ist nicht
nur für Konstruktoren,
sondern für alle
Methoden möglich.
Wofür wird ein Konstruktor benötigt?
Die Konstruktormethode hat den gleichen Namen wie die Klasse.
Konstruktormethoden dürfen keinen Rückgabewert haben.
Le
Woran erkenne ich eine Konstruktormethode?
Ein Konstruktor ist eine Methode, die beim Erzeugen
eines Objektes aufgerufen wird. Sie sorgt dafür, dass die
Eigenschaften des Objektes sinnvolle Werte annehmen.
L 7: Konstruktormethode
Erstelle für die Klasse Auto einen Konstruktor, der die Parameter Kennzeichen, Marke,
Tankinhalt und Verbrauch zwingend vorschreibt.
Der Konstruktor hat
keinen Rückgabedatentyp, void fehlt also.
Bei gleichen Variablennamen für den Parameter des Konstruktors
und die Eigenschaft
wird mit this klargestellt, welche Variable
gemeint ist.
64
// Konstruktor
public Auto(string kennzeichen, string marke,
double tankinhalt, double verbrauch)
{
this verweist auf die
this.kennzeichen = kennzeichen;
Eigenschaft
this.marke = marke;
this.tankinhalt = tankinhalt;
if (verbrauch > 0)
this.verbrauch = verbrauch;
else
throw new Exception("Der Verbrauch ist ungültig.");
fahrtkosten = 0;
}
Softwareentwicklung
Lerneinheit 1: Klassen und Objekte
In einer Klasse darf es
nur einen Destruktor
geben. Überladen und
Zugriffsmodifizierer,
z.B. public, sind nicht
erlaubt.
Auf die Verwendung von Destruktormethoden können wir in der Praxis verzichten, wenn wir
z.B. mit einer Cleanup-Methode, z.B. Dispose(), für die Freigabe der Ressourcen sorgen.
be
Statt eines Destruktors
wird zum Freigeben
von Ressourcen häufig
die Methode Dispose()
verwendet.
// Destruktor
~Auto()
{
anzahlAutos--;
}
Andere Konstruktoren mit this aufrufen
ro
Ein wichtiges Prinzip objektorientierter Programmierung ist die Wiederverwendbarkeit von Programmcode. Ein überladener Konstruktor kann sich der Implementierung eines anderen
Konstruktors mit Hilfe von : this(Parameter) bedienen. In den runden Klammern werden die
Parameter an die aufzurufende Konstruktormethode übergeben. Um einen besseren Überblick
zu erhalten, sehen wir uns nun die gesamte Klasse Auto zusammenfassend an:
L 9: Konstruktormethoden mit this wiederverwenden
Mit : this() wird zunächst der Standardkonstruktor aufgerufen.
Erst danach wird der
Codeblock des überladenen Konstruktors
ausgeführt.
Der Gebrauchtwagenkonstruktor verwendet
den Neuwagenkonstruktor und ergänzt
ihn danach.
Softwareentwicklung
sep
Der Konstruktor sorgt
für gültige Werte der
Eigenschaften, wenn
ein Objekt erzeugt
wird.
// Standardkonstruktor
public Auto()
{
fahrtkosten = 0;
}
Le
Aufgrund der Kapselung sind die Eigenschaften private.
namespace cs_Frachtkostenoptimierung
{
class Auto
{
// Eigenschaften
private string kennzeichen, marke;
private double verbrauch, tankinhalt,
kraftstoffvorrat, fahrtkosten;
// Konstruktor für einen Neuwagen
public Auto(string marke, double verbrauch)
: this() // Standardkonstruktor aufrufen
{
this.kennzeichen = "Neu";
this.marke = marke;
this.tankinhalt = 0;
if (verbrauch > 0)
this.verbrauch = verbrauch;
else
throw new Exception("Der Verbrauch ist ungültig.");
}
// Konstruktor für einen Gebrauchtwagen
public Auto(string kennzeichen, string marke,
double tankinhalt, double verbrauch)
: this(marke, verbrauch) // Neuwagenkonstruktor aufrufen
{
this.kennzeichen = kennzeichen;
this.tankinhalt = tankinhalt;
}
65
2 Objektorientiertes Programmieren
L 8: Destruktormethode
Erstelle für die Klasse Auto einen Destruktor, der die globale Variable anzahlAutos um
eins reduziert, wenn ein Auto-Objekt zerstört wird.
Üben
Die Methode Tanken
erlaubt die Veränderung der Eigenschaft
Kraftstoffvorrat und
überprüft vor der
Wertzuweisung deren
Gültigkeit.
Mit Hilfe der Properties
kann auf die gekapselten Eigenschaften zugegriffen werden.
Sichern
Wissen
// Methode Tanken
public void Tanken(double liter)
{
if (kraftstoffvorrat + liter > tankinhalt)
throw new Exception("So viel passt nicht in den Tank.");
else
kraftstoffvorrat += liter;
}
// Properties
public double Kraftstoffvorrat
{
get { return kraftstoffvorrat; }
set
{
if (kraftstoffvorrat + value > tankinhalt)
throw new Exception("Der Tank ist dafür zu klein.");
else
kraftstoffvorrat += value;
}
}
Le
sep
ro
public double Fahrtkosten
{
get { return fahrtkosten; }
}
}
}
be
Lernen
Die Klasse Auto besteht aus Eigenschaften, einer Konstruktormethode, der Methode Tanken
sowie den Properties Kraftstoffvorrat und Fahrtkosten. Nun sehen wir uns an, wie wir eine
Klasse dazu verwenden, Objekte zu erzeugen.
Instanzierung von Objekten
Wir haben bereits den Unterschied zwischen einer Klasse und einem Objekt kennengelernt: Die
Klasse Auto legt abstrakte Eigenschaften und Methoden fest, ein Objekt der Klasse Auto kann
konkrete Werte für jede Eigenschaft beinhalten.
Klasse Auto
Diese Abbildung findest
du in der PowerPointPräsentation unter der
ID: 1179.
Beachte
66
Instanz von
kennzeichen
marke
verbrauch
tankinhalt
kraftstoffvorrat
fahrtkosten
Tanken()
Kraftstoffvorrat
Fahrtkosten
Objekt Porsche
"W4711A"
"Porsche"
14.7
70
34.2
0
Tanken()
Kraftstoffvorrat
Fahrtkosten
Abb.: Instanzierung eines Objektes von einer Klasse
Das Objekt Porsche ist eine Instanz der Klasse Auto. Ein Objekt kennt die Klasse, von der
es instanziert wurde. Wir können somit die folgende Aussage über ein Porsche-Objekt
treffen: „Ein Porsche ist ein Auto.“
Softwareentwicklung
Lerneinheit 1: Klassen und Objekte
Natürlich ist das wenig überraschend. Entscheidend ist aber, dass jedes von einer Klasse instanzierte Objekt die Klasse kennt, von der es abgeleitet wurde. In der Lerneinheit 2 wird das bei der
Nutzung der Vererbung von Bedeutung sein.
Das folgende Lehrbeispiel zeigt, wie wir Objekte instanzieren und verwenden.
2 Objektorientiertes Programmieren
ro
Objekte bieten
Methoden und Properties zur Verwendung
an.
// Formularkonstruktor
public Form1()
{
InitializeComponent();
porsche.Tanken(70);
golf.Tanken(10);
golf.Kraftstoffvorrat = 5;
}
}
be
Objekte werden mittels
eines Konstruktors von
der Klasse instanziert.
L 10: Objekte instanzieren
public partial class Form1 : Form
{
Auto porsche = new Auto("W4711A", "Porsche", 70, 14.7);
Auto golf = new Auto("S457GA", "VW", 50, 6.4);
Die Objektvariablen porsche und golf werden als Klassenvariablen erzeugt. Beiden Objektvariablen wird ein neues Auto-Objekt über die Konstruktormethode der Klasse Auto zugewiesen.
Le
sep
Im Formularkonstruktor wird für jedes Auto-Objekt die Methode Tanken aufgerufen. Alternativ kann auch das Set-Property Kraftstoffvorrat zum Tanken verwendet werden.
Zur Berechnung der Fahrtkosten jedes Auto-Objektes benötigen wir neben dem Verbrauch und
der Fahrstrecke den Kraftstoffpreis. Warum wir diesen nicht einfach als Eigenschaft der Klasse
Auto erstellen können, sehen wir uns nun genauer an.
6 Statische Elemente
Eigenschaften für mehrere Objekte
Eigenschaften, wie z.B. der Benzin- bzw. Dieselpreis, sind für alle Auto-Objekte mit einem
Benzin- bzw. Dieselmotor gleich. Eine Preisänderung der Kraftstoffe wirkt sich auf alle Autos
aus. Hingegen sind der Verbrauch oder der Kraftstoffvorrat bei jedem Objekt individuell. Statische Eigenschaften gelten auf Klassenebene und sind für alle Objekte gleich. Sie können nur
durch statische Methoden geändert werden.
Auto
Die Preisänderung erfolgt über eine statische
Methode.
Diese Abbildung findest
du in der PowerPointPräsentation unter der
ID: 1179.
Softwareentwicklung
kraftstoffvorrat
fahrtkosten
benzinpreis
dieselpreis
Tanken()
Fahren()
Kraftstoffvorrat
Fahrtkosten
Preisänderung()
Abb.: Statische Elemente betreffen alle Objekte einer Klasse
67
Lernen
Üben
Sichern
Wissen
1 Der Wert einer statischen Eigenschaft gilt für alle Objekte einer Klasse.
Benzinpreis und Dieselpreis sind statische Eigenschaften. Deren Werte gelten für alle
Objekte der Klasse Auto. Der Wert einer statischen Eigenschaft kann nur über die Klasse
zugewiesen werden, nicht über das Objekt wie bei den Objekt-Eigenschaften.
3 Statische Eigenschaften können nur durch statische Methoden oder die Referenzierung über den Klassennamen verändert werden.
Die statische Methode Preisänderung() ändert die statischen Eigenschaften Benzinpreis
und Dieselpreis. Preisänderung() wird über die Klasse aufgerufen – nicht über das Objekt, wie eine nicht-statische Methode.
4 Statische Elemente erhalten das Schlüsselwort static.
Um eine statische Eigenschaft oder eine statische Methode zu erstellen, wird das
Schlüsselwort static bei der Deklaration verwendet, z.B. private static double benzinpreis oder public static void Preisänderung(double benzin, double diesel) { ... }.
ro
Das Verändern einer
statischen Eigenschaft
durch eine nichtstatische Methode ist
durch die Angabe des
Klassennamens möglich, z.B. public void
ChangePreis() { Auto.
benzinpreis = 1.15; }
2 Nicht-statische Methoden können statische Eigenschaften lesen, aber nicht verändern. Zum Ändern muss die statische Eigenschaft über die Klasse aufgerufen
werden.
Die nicht-statische Methode Tanken() kann den Benzin- bzw. Dieselpreis zwar lesen, aber
nicht verändern. Dafür ist eine statische Methode oder die Angabe der Klasse erforderlich.
be
Wird eine statische
Eigenschaft über die
Klasse angesprochen,
kann diese gelesen und
geändert werden, auch
von einem Objekt aus.
sep
5 Wertzuweisungen an statische Eigenschaften erfolgen über einen statischen
Konstruktor.
Wertzuweisungen an Objekt-Eigenschaften erfolgen über einen Konstruktor, wenn das
Objekt erzeugt wird. Da statische Eigenschaften selbst dann einen Wert erhalten könnten,
wenn es keine Objekte gibt, muss die Wertzuweisung über die Klasse, also einen statischen
Konstruktor, erfolgen.
Das folgende Lehrbeispiel zeigt die Verwendung der statischen Elemente.
L 11: Statische Elemente in einer Klasse
Erstelle für die Klasse Auto die statischen Eigenschaften Benzinpreis und Dieselpreis mit
einem statischen Konstruktor sowie eine Methode zur Änderung beider Kraftstoffpreise.
Der statische Konstruktor weist den statischen
Eigenschaften gültige
Werte zu. Ein statischer
Konstruktor kann nicht
überladen werden.
Die Wertänderung
statischer Eigenschaften
ist über die statische
Methode Preisänderung
möglich.
Falls die Methode Preisänderung nicht statisch
wäre, müssten die statischen Eigenschaften
über die Klasse Auto
angesprochen werden,
z.B. Auto.benzinpreis.
68
Le
// Statische Eigenschaften
private static double benzinpreis, dieselpreis;
// Statischer
public static
{
benzinpreis
dieselpreis
}
Konstruktor
Auto()
= 1.1;
= 1.05;
// Statische Methode
als nicht-statische Methode:
public static void Preisänderung
(double benzin, double diesel)
public void Preisänderung(..)
{
{ ..
if (benzin > 0 && diesel > 0)
Auto.benzinpreis = benzin;
{
Auto.dieselpreis = diesel;
benzinpreis = benzin;
.. }
dieselpreis = diesel;
}
else
throw new Exception("Ungültiger Kraftstoffpreis.");
}
Softwareentwicklung
Lerneinheit 1: Klassen und Objekte
Wir können uns den Einsatz eines statischen Konstruktors ersparen, wenn wir die Wertzuweisung bei der Deklaration der statischen Eigenschaften vornehmen. Außerdem kann
statt einer statischen Methode zur Preisänderung auch ein statisches Property verwendet
werden.
2 Objektorientiertes Programmieren
// Statische Eigenschaften mit Wertzuweisung
private static double benzinpreis = 1.1;
private static double dieselpreis = 1.05;
be
// Statische Set-Properties
public static double Benzinpreis
{
set
{
if (value > 0)
benzinpreis = value;
else
throw new Exception("Ungültiger Benzinpreis.");
}
}
Mr. What und
Ms. Check
sep
ro
public static double Dieselpreis
{
set
{
if (value > 0)
dieselpreis = value;
else
throw new Exception("Ungültiger Dieselpreis.");
}
}
Wodurch unterscheiden sich statische
von nicht-statischen Eigenschaften?
Nein, aber eine nicht-statische Methode kann den Wert einer
statischen Eigenschaft ansprechen.
Le
Kann eine statische Methode
auf nicht-statische Eigenschaften
zugreifen?
Die Werte statischer Eigenschaften gelten auf Klassenebene und sind somit für alle Objekte lesbar, nicht-statische hingegen gelten nur für das jeweilige Objekt.
Du hast nun alle erforderlichen Grundlagen für die Erstellung der Klasse Auto kennengelernt.
Die folgenden Aufgaben helfen dir dabei, deine Kenntnisse anzuwenden und zu vertiefen.
Üben
Übungsbeispiele
Softwareentwicklung
Ü 4:
Erweitere die Klasse Auto um die Eigenschaft Diesel vom Datentyp Bool. Berücksichtige dies
auch bei den Konstruktoren, denn die Kraftstoffart muss zur Erzeugung von Auto-Objekten
mittels True oder False angegeben werden.
69
Lernen
Üben
Sichern
Wissen
Ü 5:
Erweitere die Klasse Auto um die Methode Fahren(km) und berücksichtige dabei folgende
Anforderungen:
1. Der Parameter km hat den Datentyp Double.
2. Autos dürfen nur vorwärts fahren.
3. Autos dürfen nur fahren, wenn genug Kraftstoffvorrat für die Fahrstrecke vorhanden ist.
4. Vermindere den Kraftstoffvorrat um den Kraftstoffverbrauch für die zurückgelegte Fahrstrecke.

Ü 6:
Erweitere die Klasse Auto um die Eigenschaft Tankwert vom Datentyp Double. Diese Eigenschaft repräsentiert den Gesamtwert des Kraftstoffvorrats, der sich aktuell im Tank eines
Autos befindet.
be
a) Erweitere die Methode Tanken so, dass Tankwert um das Produkt aus Liter und Kraftstoffpreis erhöht wird. Berücksichtige, ob das Auto einen Benzin- oder Dieselmotor hat. Dafür
benötigst du die Eigenschaft Diesel aus Ü 4.
b) Ergänze die Methode Fahren aus Ü 5 um die Erhöhung der Fahrtkosten. Die Formel dafür
lautet Fahrtkosten + Tankwert / Kraftstoffvorrat * Verbrauch / 100 * Fahrstrecke.
In diesem komplexen
Übungsbeispiel verwendest du alle bisher gelernten Basiskonzepte
der objektorientierten
Programmierung.
Ü 7:
Pedro’s Pizzeria
Erstelle eine neue C#-Projektdatei „cs_Pizzeria“ mit Visual Studio 2005 und darin die Klasse Pizza wie folgt:
ro

sep
a) Jede Pizza hat die Eigenschaften Tischnummer vom Typ Integer, Zutaten vom Typ String
sowie Pizzapreis vom Typ Double.
b) Jede Pizza besteht mindestens aus den Zutaten „Teig“, „Tomatensauce“ und „Käse“ und hat
einen Grundpreis von 4,50 EUR. Füge diese Zutaten im Standardkonstruktor als Text an die
Eigenschaft Zutaten an und setze die Eigenschaft Pizzapreis auf den Grundpreis.
c) Erstelle ein Set-Property für die Eigenschaft Zutaten, das diese um den als Wert übergebenen Text erweitert. Bereits bestellte Zutaten dürfen dadurch nicht überschrieben werden.
Erhöhe die Zutatenanzahl um 1.
d) Erstelle ein Get-Property für die Eigenschaft Zutaten.
Le
e) Erstelle einen überladenen Konstruktor ähnlich dem Standardkonstrukor, wobei zusätzlich
als Parameter die Tischnummer übergeben wird. Im Restaurant gibt es 14 Tische. Weise die
Tischnummer der Eigenschaft Tischnummer zu.
f) Erstelle die statische Eigenschaft Zutatenpreis, die für jeden zusätzlich gewählten Pizzabelag
einen einheitlichen Preis von 0,50 EUR festlegt. Das Set-Property für die Eigenschaft Zutaten
soll den Pizzapreis um den Zutatenpreis erhöhen, wenn der Belag einer Pizza um eine zusätzliche Zutat ergänzt wird.
g) Erstelle die Methode Preiserhöhung ohne Parameter, die den Zutatenpreis bei jedem Aufruf
um 2 % erhöht.
h) Erstelle ein Set-Property für die Eigenschaft Zutatenpreis.
Zusätzlich zu diesen Übungen findest du in SbX eine Internetaufgabe.
ID: 1180
70
Softwareentwicklung
Lerneinheit 1: Klassen und Objekte
Sichern
Eine Klasse beschreibt allgemeine abstrakte Merkmale, die für alle der Klasse zugehörigen
Objekte gültig sind. Eine Klasse beinhaltet Eigenschaften und Methoden.
Objekt
Ein Objekt ist eine Instanz einer Klasse. Es hat konkrete Ausprägungen in Form von Eigenschaften und Methoden. Ein Objekt erbt alle Eigenschaften und Methoden von einer Klasse.
Vererbung
Eine Klasse kann ein Abbild einer Basisklasse sein. Als Subklasse erbt sie alle Eigenschaften
und Methoden der Basisklasse.
Kapselung
Eigenschaften einer Klasse werden als private Variablen festgelegt. Dadurch wird ein unkontrollierter Zugriff auf Eigenschaften verhindert. Nur Methoden erhalten Zugang zu den Eigenschaften ihrer Klasse. Durch Kapselung wird erreicht, dass eine Klasse bzw. ein Objekt möglichst eigenverantwortlich und losgelöst vom aufrufenden Programm agieren kann.
Zugriffsmethode
Ein Property ist eine Zugriffsmethode für eine Eigenschaft. Properties sind nötig, da Eigenschaften aufgrund der Kapselung nur innerhalb der Klasse verfügbar sind. Nach der Zugriffsberechtigung werden Get- und Set-Properties unterschieden.
ro
be
Klasse
Ein Get-Property darf Eigenschaften einer Klasse lesen.
Set-Property
Ein Set-Property darf Eigenschaften einer Klasse verändern.
Konstruktor
Eine Konstruktormethode wird bei der Erzeugung eines Objektes aufgerufen. Konstruktoren können mit Hilfe sich unterscheidender Datentypen bei den Parametern überladen werden. Eine Konstruktormethode legt die Art und Weise fest, unter welchen Bedingungen ein
Objekt erzeugt werden darf.
Destruktor
sep
Get-Property
Die Destruktormethode einer Klasse wird bei der Zerstörung eines Objektes aufgerufen.
Der Wert einer statischen Eigenschaft wird entweder direkt bei der Deklaration oder über
die Klasse in Form eines statischen Konstruktors, einer statischen Methode oder eines statischen Propertys festgelegt. Objekte können statische Eigenschaften lesen, jedoch nicht verändern.
Statische
Methode
Eine statische Methode dient der Änderung eines Wertes einer statischen Eigenschaft.
Auch statische Properties können dafür verwendet werden.
Le
Statische
Eigenschaft
Zusätzlich zu dieser Zusammenfassung findest du in SbX eine Bildschirmpräsentation.
ID: 1181
Wissen
Wiederholungsfragen und -aufgaben
1.Erkläre den Unterschied zwischen Klasse und Objekt!
2.Welche Bestandteile hat eine Klasse?
3.Warum ist die Kapselung ein wichtiger Grundsatz objektorientierter Programmierung?
Softwareentwicklung
71
2 Objektorientiertes Programmieren
In dieser Lerneinheit haben wir die wichtigsten Bestandteile von Klassen und Objekten
kennengelernt:
Lernen
Üben
Sichern
Wissen
4.Erkläre das Prinzip der Vererbung sowie die Begriffe Basis- und Subklasse!
5.Wofür werden Properties verwendet?
6.Erkläre die verschiedenen Erscheinungsformen von Properties!
7.Beschreibe mögliche Gefahren bei Missachtung des Grundsatzes der Kapselung!
8.Erkläre den Unterschied zwischen private und protected anhand einer Eigenschaft in einer
Subklasse!
9.Erkläre den Unterschied zwischen einer statischen und einer nicht-statischen Eigenschaft!
be
10.Kann eine nicht-statische Methode den Wert einer statischen Eigenschaft lesen bzw. verändern?
11.Kann eine statische Methode den Wert einer nicht-statischen Eigenschaft lesen bzw. verändern?
Zusätzlich zu diesen Aufgaben findest du in SbX ein Quiz.
Lerncheck
Ich kann jetzt …
ro
ID: 1182
w ... den Unterschied und die Verwendung von Klassen und Objekten erklären.
sep
w ... Eigenschaften und Methoden als wichtige Bestandteile von Klassen und Objekten beschreiben.
w ... Kapselung und Vererbung als Grundprinzipien objektorientierter Programmierung nennen.
w ... die Verwendung von Properties im Zusammenhang mit Eigenschaften einer Klasse erklären.
w ... Konstruktoren überladen und zur Erzeugung von Objekten verwenden.
w ... statische Eigenschaften und statische Methoden richtig einsetzen.
Le
In der nächsten Lerneinheit beschäftigen wir uns mit dem Einsatz der Vererbung von Klassen
sowie dem Überschreiben von virtuellen Methoden und der Anwendung der Polymorphie.
72
Softwareentwicklung
Lerneinheit 2: Vererbung
Lerneinheit 2
Vererbung
In dieser Lerneinheit beschäftigen wir uns mit den Konzepten der Vererbung und
der Polymorphie sowie dem Einsatz von Interfaces.
Wir erweitern das bereits in der Lerneinheit 1 begonnene Lehrbeispiel zur Frachtkostenoptimierung um
2 Objektorientiertes Programmieren
Alle SbX-Inhalte zu dieser Lerneinheit findest
du unter der ID: 1183.
be
● die Vererbung von Klassen und Konstruktoren,
● das Überschreiben virtueller Methoden (Polymorphie),
● die Verwendung abstrakter und versiegelter Klassen sowie
● die Verwendung der Mehrfachvererbung mit Hilfe von Interfaces.
ro
Lernen
1 Subklassen
Klassen vererben
L 1:
Der Fuhrpark eines Unternehmens besteht aus LKWs und PKWs. Für beide Fahrzeugkategorien sollen unterschiedliche Klassen erstellt werden, da PKWs und LKWs unterschiedliche Eigenschaften haben. Für einen LKW muss zur Berechnung der Autobahnmaut die Achszahl
bekannt sein, PKWs benötigen eine Vignette. Eine einfache Lösung besteht darin, eine gemeinsame Basisklasse Auto zu erstellen und die beiden Subklassen PKW und LKW davon
abzuleiten.
Le
Das komplexe
Fallbeispiel Fuhrpark
findest du unter der
ID: 1184.
sep
Wir haben in der ersten Lerneinheit anhand der Klasse Auto die Bestandteile einer Klasse besprochen. Diese Klasse dient als Basis für die weitere Entwicklung unseres Fallbeispieles für die
Frachtkostenoptimierung eines Fuhrparks.
Auto
Die Basisklasse Auto
enthält allgemein
gültige Eigenschaften
und Methoden.
marke
verbrauch
...
Tanken()
Fahren()
PKW
Diese Abbildung findest
du in der PowerPointPräsentation unter der
ID: 1184.
Softwareentwicklung
vignette
LKW
achszahl
Die Subklassen PKW
und LKW erweitern
oder verändern die
Eigenschaften und
Methoden der Basisklasse.
Abb.: Vererbung von Basisklassen an Subklassen
73
Lernen
Üben
Sichern
Wissen
Wiederverwendbarkeit durch Vererbung
Die Abbildung zeigt, dass sich PKWs von LKWs nur durch die Eigenschaften Vignette und
Achszahl unterscheiden. Alle anderen Bestandteile sind gleich.
Ein wichtiges Prinzip beim objektorientierten Programmieren ist die Wiederverwendbarkeit
von Programmcode. Wir erstellen daher die Klasse Auto mit den gemeinsamen Merkmalen beider Subklassen. Die speziellen Eigenschaften Vignette und Achszahl werden in den
Subklassen ergänzt.
Eine spätere Erweiterung, z.B. das Hinzufügen der Frachtkapazität, wird in der Basisklasse vorgenommen. Die Frachtkapazität steht durch die Vererbung in allen Subklassen zur Verfügung.
Vererbung verwenden
be
1 Eine Subklasse greift auf die Elemente ihrer Basisklasse zu.
Die Subklassen PKW und LKW kennen die Eigenschaften und Methoden der Basisklasse
Auto. Alle Elemente der Basisklasse werden an die Subklassen vererbt – sofern der Zugriffsmodifizierer dies erlaubt.
2 Der Zugriffsmodifizierer legt fest, ob auf eine Eigenschaft einer Klasse zugegriffen werden darf.
ro
Der Zugriffsmodifizierer private legt den Zugriff auf die eigene Klasse fest. Aus einer
Subklasse ist der Zugriff nicht möglich. Private Eigenschaften werden nicht vererbt!
Der Zugriffsmodifizierer protected erlaubt den Zugriff für die eigene Klasse und für alle
von dieser Klasse abgeleiteten Subklassen. Sollen die Eigenschaften der Basisklasse an die
Subklassen vererbt werden, müssen wir protected verwenden.
Der Zugriffsmodifizierer public erlaubt den Zugriff für alle Klassen.
sep
3 Von einer abstrakten Klasse dürfen keine Objekte instanziert werden.
Wird für eine Klasse das Schlüsselwort abstract benutzt, muss es mindestens eine Subklasse
geben, wenn Objekte erzeugt werden sollen. Eine abstrakte Klasse verbietet das Instanzieren von Objekten.
4 Von einer versiegelten Klasse können keine Subklassen abgeleitet werden.
Le
Wenn von einer Klasse keine weiteren Subklassen mehr abgeleitet werden dürfen, muss
die Klasse mit dem Schlüsselwort sealed versiegelt werden.
Auto
marke
verbrauch
...
protected
Tanken()
Fahren()
Eigenschaften
werden vererbt
PKW
Diese Abbildung findest
du in der PowerPointPräsentation unter der
ID: 1184.
74
LKW
marke
verbrauch
...
vignette
marke
verbrauch
...
achszahl
Tanken()
Fahren()
Tanken()
Fahren()
zusätzliche
Eigenschaften
Abb.: Eigenschaften und Methoden in Subklassen
Softwareentwicklung
Lerneinheit 2: Vererbung
Der Zugriffsmodifizierer protected kapselt die Eigenschaften innerhalb der Klasse Auto und
ihrer Subklassen PKW und LKW. Der Zugriff für andere Klassen ist nicht zulässig. Die Methoden
Tanken() und Fahren() sind hingegen weiterhin öffentlich (public) und damit auch für andere
Klassen verwendbar.
Eine Subklasse erbt alle nicht privaten Eigenschaften, Methoden und Zugriffsmethoden von ihrer Basisklasse. Konstruktormethoden werden nicht vererbt!
2 Objektorientiertes Programmieren
Beachte
// Basisklasse Auto
abstract class Auto
{
// Eigenschaften
protected string marke;
protected double verbrauch, tankinhalt,
fahrtkosten, kraftstoffvorrat;
ro
Da nur von den Subklassen PKW und LKW
Objekte erzeugt werden dürfen, ist Auto
eine abstrakte Klasse.
be
L 2: Vererbung anwenden
Erstelle die Basisklasse Auto sowie die beiden Subklassen PKW und LKW gemäß der Abbildung auf Seite 74.
// Methoden
public void Tanken() {
kraftstoffvorrat = tankinhalt;
}
Die Vererbung erfolgt
mit einem Doppelpunkt
und der Angabe der
Basisklasse.
public void Fahren() {
// do something
}
}
sep
Die Implementierung
der Methode Fahren()
erfolgt später.
// Subklasse für PKWs
class Pkw : Auto
{
private bool vignette;
}
Mr. What und
Ms. Check
Le
// Subklasse für LKWs
class Lkw : Auto
{
private byte achszahl;
}
Wie kann ich ein Objekt von einer
Subklasse instanzieren, wenn die
Konstruktormethoden nicht vererbt
werden?
Können statische Eigenschaften
und Methoden auch vererbt
werden?
Jede Klasse hat einen Standardkonstruktor, wenn du
keine eigenen Konstruktoren implementierst. Das gilt
auch für Subklassen – aber nur, wenn es in der Basisklasse
auch einen Standardkonstruktor gibt!
Ja, alle statischen und nicht-statischen Elemente werden vererbt. Die Konstruktoren werden nicht vererbt.
Wie wir bereits erfahren haben, werden Konstruktormethoden nicht vererbt. Sehen wir uns an,
wie wir dennoch die vorhandenen Konstruktormethoden einer Basisklasse verwenden können.
Softwareentwicklung
75
Lernen
Üben
Sichern
Wissen
2 Konstruktoren in Subklassen
Konstruktormethoden wiederverwenden
Das Lehrbeispiel L 2 funktioniert, da wir keine speziellen Konstruktormethoden verwendet
haben. Aus allen Klassen können Objekte instanziert werden. Was passiert aber, wenn in einer
Basisklasse überladene Konstruktormethoden vorhanden sind? Sehen wir uns dazu das folgende Lehrbeispiel an!
L 3: Vererbung und Konstruktoren
Die Klasse Auto aus dem Lehrbeispiel L 2 soll um eine Konstruktormethode mit den
Parametern Marke und Kraftstoffvorrat erweitert werden.
sep
ro
be
// Basisklasse Auto
class Auto
{
// Eigenschaften
protected string marke;
protected double verbrauch, tankinhalt,
fahrtkosten, kraftstoffvorrat;
// Konstruktor
public Auto(string marke, double verbrauch, double tank) {
this.marke = marke;
this.verbrauch = verbrauch;
this.tankinhalt = tank;
this.kraftstoffvorrat = 0;
this.fahrtkosten = 0;
}
// Methoden
public void Tanken() {
kraftstoffvorrat = tankinhalt;
}
public void Fahren() {
// do something
}
}
Fehler! –>
Le
// Subklasse PKW
class Pkw : Auto
{
private bool vignette;
}
// Objekt instanzieren
Pkw audi = new Pkw();
Diese Konstruktormethode fehlt in
der Basisklasse.
Das Objekt audi wird bottom-up erzeugt, d.h. es werden der Reihe nach alle Konstruktoren der
Subklassen bis hin zur Basisklasse aufgerufen.
Wenn es in einer Klasse keine überladenen Konstruktormethoden gibt, wird vom Compiler
automatisch ein Standardkonstruktor erzeugt. Das gilt auch für die Subklasse PKW.
Da das Audi-Objekt bottom-up erzeugt wird, verlangt der Standardkonstruktor in der Subklasse PKW auch nach einem Standardkonstruktor in der Basisklasse Auto. Doch diesen gibt es
nicht und wir erhalten in der Folge einen Compilierfehler.
Beachte
76
In einer Basisklasse muss es Konstruktormethoden geben, deren sich die SubklassenKonstruktormethoden bedienen können.
Softwareentwicklung
Lerneinheit 2: Vererbung
L 4: Basisklassen-Konstruktor verwenden
Die Subklasse PKW aus dem Lehrbeispiel L 3 soll so verändert werden, dass PKWObjekte instanziert werden können.
be
public Pkw(string marke, double verbrauch, double tank)
: base(marke, verbrauch, tank)
{
this.vignette = false;
}
public Pkw(string marke, double verbrauch,
double tank, bool vignette)
: base(marke, verbrauch, tank)
{
this.vignette = vignette;
}
}
ro
Beide Subklassenkonstruktoren rufen
denselben Basisklassenkonstruktor auf.
2 Objektorientiertes Programmieren
// Subklasse PKW
class Pkw : Auto
{
private bool vignette;
Konstruktoren wiederverwenden
1 Konstruktormethoden werden nicht vererbt und müssen daher in der Subklasse
neu deklariert werden.
sep
Die Konstruktormethode Auto(marke, kraftstoffvorrat) muss auch in der Subklasse PKW
implementiert werden. Jede Klasse, egal ob Basisklasse oder Subklasse, muss alle benötigten
Konstruktormethoden implementieren.
2 Mit base wird die Basisklasse angesprochen.
Mit Hilfe von base ruft die Subklassen-Konstruktormethode PKW(marke, kraftstoffvorrat)
die Basisklassen-Konstruktormethode Auto(marke, kraftstoffvorrat) auf. Alle dort implementierten Anweisungen werden zunächst ausgeführt, danach die im Subklassenkonstruktor
zusätzlich festgelegten.
Le
3 Eine Subklasse kann zusätzliche Konstruktormethoden implementieren, die sich
eines gemeinsamen Basisklassenkonstruktors bedienen.
Die überladene Subklassen-Konstruktormethode PKW(marke, kraftstoffvorrat, vignette)
ruft denselben Basisklassenkonstruktor auf, wie der Konstruktor PKW(marke, kraftstoffvorrat).
Ü 1:
Ergänze zum Lehrbeispiel L 4 die Subklasse Lkw mit dem Konstruktor Lkw(marke,
verbrauch, tankinhalt, achszahl). Ein LKW ohne Angabe der Achszahl darf nicht instanziert werden.
Mr. What und
Ms. Check
Softwareentwicklung
Kann ich mit base auch Methoden, wie z.B. Fahren(), aus der
Basisklasse aufrufen?
Ja, das ist z.B. sinnvoll, wenn du die Methode der Basisklasse
um zusätzliche Anweisungen erweitern möchtest.
77
Lernen
Üben
Sichern
Wissen
3 Methoden überschreiben
Unterschiedliches Verhalten von Objekten
Sehen wir uns die beiden Methoden der Basisklasse Auto genauer an. Die Methode Tanken()
kann für PKWs und LKWs in der gleichen Art und Weise eingesetzt werden. Sie erhöht den
Kraftstoffvorrat um die getankte Menge und sorgt dafür, dass der Tank nicht überfüllt wird.
Für Autobahnfahrten benötigt ein PKW eine Vignette, ein LKW bezahlt hingegen einen von
der Achszahl abhängigen Mautsatz pro Autobahnkilometer. In der Basisklasse wird die
folgende Methode Fahren() hinzugefügt:
be
sep
Da die Basisklasse für
PKWs und LKWs gilt,
können nur die allgemeinen Fahrtkosten
berechnet werden, die
zusätzlichen Fahrtkosten für Autobahnfahrten jedoch nicht.
ro
Hinweis:
Wir gehen vereinfacht
davon aus, dass Benzin
und Diesel gleich viel
kosten.
// Fahren-Methode der Basisklasse Auto
public void Fahren(int km, bool autobahn)
{
// Kraftstoffpreis
double preis = 1.15;
if (km <= 0)
throw new Exception("Das Auto darf nicht rückwärts fahren!");
else
{
if (kraftstoffvorrat < km * verbrauch / 100)
throw new Exception("Zu wenig Kraftstoff im Tank!");
else
{
kraftstoffvorrat –= km * verbrauch / 100;
fahrtkosten += km * verbrauch / 100 * preis;
}
}
}
Die Fahren-Methode der Basisklasse aktualisiert den Kraftstoffvorrat und erhöht die Fahrtkosten um die Kosten für den verbrauchten Treibstoff. Da ein PKW für eine Autobahnfahrt eine
Vignette haben muss und ein LKW pro Kilometer bezahlt, können diese Kosten in der Basisklasse
noch nicht berechnet werden. Diese Ergänzung müssen wir in den Subklassen vornehmen:
Ein PKW benötigt für
Autobahnfahrten eine
Vignette, die Fahrtkosten erhöhen sich um
deren Anschaffungspreis.
Ein LKW bezahlt einen
Mautsatz pro Kilometer,
der von seiner Achszahl
abhängig ist.
78
Le
Aufruf der FahrenMethode in der
Basisklasse.
// Fahren-Methode der Subklasse PKW
public void Fahren(int km, bool autobahn)
{
base.Fahren(km, autobahn);
if (autobahn == true && vignette == false)
{
fahrtkosten += vignettenpreis; // Vignette kaufen
vignette = true; // Vignette aufkleben
}
}
// Fahren-Methode der Subklasse LKW
public void Fahren(int km, bool autobahn)
{
base.Fahren(km, autobahn);
if (autobahn == true)
{
switch (achszahl)
{
case 2: fahrtkosten += km * 0.13; break;
case 3: fahrtkosten += km * 0.182; break;
default: fahrtkosten += km * 0.273; break;
}
}
}
Softwareentwicklung
Lerneinheit 2: Vererbung
Die Fahren-Methoden der Subklassen überschreiben die Fahren-Methode der Basisklasse.
Wir können PKW- und LKW-Objekte erzeugen, die bei Autobahnfahrten ein unterschiedliches
Verhalten haben:
L 5: Objekte aus Subklassen instanzieren
Wir erzeugen ein PKW- und ein LKW-Objekt und lassen beide Objekte 200 km auf der
Autobahn fahren.
2 Objektorientiertes Programmieren
// Ausgabe der Fahrtkosten beider Objekte
MessageBox.Show("Fahrtkosten von " + auto1.Marke + ": "
+ Convert.ToString(auto1.Fahrtkosten));
MessageBox.Show("Fahrtkosten von " + auto2.Marke + ": "
+ Convert.ToString(auto2.Fahrtkosten));
Kann ich die Autos des Fuhrparks auch in einem Array verwalten?
Ein Array verlangt nach der Angabe eines Datentyps, aber wir
haben zwei – PKW und LKW. Du kannst trotzdem ein Array erstellen, wenn du dafür als Datentyp Auto verwendest.
sep
Mr. What und
Ms. Check
// 200 km Autobahnfahrt (true)
be
Hinweis:
Marke und Fahrtkosten
müssen als Properties in
der Basisklasse implementiert werden.
// Objekte fahren
auto1.Fahren(200, true);
auto2.Fahren(200, true);
ro
Zur Objektinstanzierung werden die Subklassen-Konstruktormethoden aufgerufen.
// Formularklasse: Klassenvariablen und Objekte instanzieren
// Subklassen-Konstruktoraufruf
Pkw auto1 = new Pkw("Mercedes", 7.5, 70, true); // mit Vignette
Lkw auto2 = new Lkw("Actros", 15.3, 250, 5); // mit fünf Achsen
4 Polymorphie
Spätes Binden von Objekten
Beachte
Le
Im Lehrbeispiel L 5 wurde deutlich, dass für die Verwaltung mehrerer PKWs und LKWs in einem
Fuhrpark ein Array sinnvoll eingesetzt werden kann. Allerdings stoßen wir hier auf ein Problem,
denn bei der Deklaration des Arrays müssen wir einen Datentyp angeben – aber welchen?
Jedes Objekt einer Subklasse lässt sich in den Typ der Basisklasse casten.
L 6: Objekte in den Basisklassentyp casten
Für die Verwaltung des Fuhrparks wird ein Array vom Typ der Basisklasse Auto verwendet.
Jedes PKW- und LKWObjekt erscheint im
Array als Auto.
Die Subklassen PKW
und LKW bieten verschiedene Konstruktormethoden an.
// Fuhrpark-Array mit PKW- und LKW-Objekten
Auto[] fuhrpark =
{
new Pkw("Mercedes", 7.5, 70, true),
Die PKW- und LKW-Objekte
new Lkw("Actros", 15.3, 250, 5),
werden implizit in den Typ
new Pkw("VW Sprinter", 9.2, 80)
Auto gecastet.
};
Das Fuhrpark-Array enthält PKWs und LKWs, die nach außen als Autos erscheinen. Dennoch
weiß jedes Objekt, dass es entweder ein PKW oder ein LKW ist.
Softwareentwicklung
79
Lernen
Üben
Sichern
Wissen
Damit das Fuhrpark-Array mit den Objekten aus dem Lehrbeispiel L 6 richtig funktioniert, nehmen wir an den Fahren-Methoden der Basis- und Subklassen eine kleine Ergänzung vor.
e
e.
ein d
st etho
i
en M
hr elle
a
F tu
vir
Auto
marke
kraftstoffvorrat
fahrtkosten
Tanken()
virtual Fahren()
ird
n w ben.
e
r
h
Fa schrie
r
übe
vignette
achszahl
override Fahren()
override Fahren()
Abb.: Polymorphie durch spätes Binden
ro
Diese Abbildung findest
du in der PowerPointPräsentation unter der
ID: 1184.
?
LKW
be
PKW
?
Virtuelle Methoden überschreiben
1 Wenn eine Methode der Basisklasse in den Subklassen überschrieben werden
soll, wird die Basisklassenmethode als virtuelle Methode gekennzeichnet.
Die Fahren-Methode wird in der Basisklasse Auto mit dem Schlüsselwort virtual versehen.
sep
2 Die virtuelle Basisklassenmethode muss in jeder Subklasse als überschreibende
Methode neu implementiert werden.
Die Fahren-Methoden in den Subklassen PKW und LKW müssen mit dem Schlüsselwort
override versehen werden, da die virtuelle Basisklassenmethode dies zwingend vorschreibt.
Late Binding =
spätes Binden
3 Der Aufruf der virtuellen Basisklassenmethode bewirkt den automatischen Aufruf der überschreibenden Subklassenmethode. Welche Subklassenmethode aufgerufen wird, bestimmt das Objekt. Dies wird als spätes Binden bezeichnet.
Le
Im Fuhrpark-Array erscheint jedes Objekt als Auto, nicht als PKW oder LKW. Daher ruft die
Methode Fahren() zunächst die virtuelle Methode der Klasse Auto auf. Je nachdem,
welches Objekt angesprochen wird, PKW oder LKW, wird die entsprechende FahrenMethode der Subklasse ausgeführt.
Das folgende Lehrbeispiel veranschaulicht, wie mit Hilfe einer Schleife alle Objekte des Fuhrparks
200 km auf der Autobahn fahren. Die Fahrtkosten werden dabei für PKWs und LKWs durch das
späte Binden unterschiedlich berechnet.
L 7: Polymorphie
Die virtuelle Methode Fahren() wird in den Subklassen überschrieben.
Das Fallbeispiel Fuhrpark_Polymorphie
findest du unter der
ID: 1184.
Die Fahren-Implementierung der Basisklasse
wird mit base aufgerufen.
80
// Fahren-Methode in der Klasse Auto
public virtual void Fahren(int km, bool autobahn)
{
// do something
}
// Fahren-Methode in den Subklassen PKW und LKW
public override void Fahren(int km, bool autobahn)
{
base.Fahren(km, autobahn);
// do something else
}
Softwareentwicklung
Lerneinheit 2: Vererbung
Die polymorphe Methode Fahren() funktioniert mit unterschiedlichen Objekten – egal ob
PKW oder LKW, und ruft die entsprechenden überschriebenen Methoden der Klassen PKW und
LKW auf.
be
Kann ich statt eines Arrays auch
eine ArrayList für den Fuhrpark
verwenden?
Ja, eine ArrayList-Collection ist sogar eine noch bessere Lösung,
da du Objekte jederzeit hinzufügen und entfernen kannst.
sep
Mr. What und
Ms. Check
foreach(Auto auto in fuhrpark)
{
auto.Fahren(200, true); // 200 km Autobahnfahrt (true)
}
ro
Die foreach-Schleife
iteriert durch das Array
fuhrpark und repräsentiert in jedem Schleifendurchlauf ein anderes
Objekt in der Variable
auto.
Auto[] fuhrpark =
{
new Pkw("Mercedes", 7.5, 70, true),
new Lkw("Actros", 15.3, 250, 5),
new Pkw("VW Sprinter", 9.2, 80)
};
Ü 2:
Verändere das Lehrbeispiel L 8 so, dass statt einem Array eine ArrayList für den Fuhrpark
verwendet wird. Hinweis: Du musst dafür den Collection-Namensraum einbinden.
5 Abstrakte und versiegelte Klassen
Instanzen und Vererbung verbieten
Le
Um die Klassen PKW und LKW besser abzusichern, sollten wir das Erzeugen von Objekten aus
der Klasse Auto verbieten. Nur Instanzen von PKW und LKW dürfen möglich sein, wenn wir die
Polymorphie nutzen wollen. Die Klasse Auto ist eine abstrakte Klasse.
1 Das Instanzieren von Objekten aus einer abstrakten Klasse ist nicht zulässig.
Wenn wir die Klasse Auto als abstrakte Klasse festlegen, dürfen nur noch PKW- und
LKW-Objekte erzeugt werden. Das Schlüsselwort abstract definiert eine abstrakte Klasse.
abstract class Auto { }
Auto auto;
auto = new Auto(); –> Konstruktoraufruf ist nicht mehr zulässig!
Auto auto ist zulässig, da hier kein Objekt instanziert, sondern lediglich eine Objektvariable
deklariert wird. Der Konstruktoraufruf von Auto ist nicht erlaubt.
2 Eine versiegelte Klasse erlaubt keine weitere Vererbung mehr.
Wird die Klasse PKW versiegelt, darf keine Subklasse von PKW, wie z.B. Sportwagen, abgeleitet werden. Zum Versiegeln wird das Schlüsselwort sealed verwendet.
sealed class Pkw { }
class Sportwagen : Pkw { } –> Vererbung ist nicht mehr zulässig!
Die Vererbung ist nicht zulässig, da die Klasse PKW versiegelt ist.
Softwareentwicklung
81
2 Objektorientiertes Programmieren
L 8: Polymorphie mit Objekten
Alle Objekte des Fuhrparks fahren 200 km auf der Autobahn.
Lernen
Üben
Mr. What und
Ms. Check
Sichern
Wissen
Warum sollte ich abstrakte und
versiegelte Klassen einsetzen?
Klassen sollten möglichst sicher und gegen Fehler resistent
sein. Mit abstrakten und versiegelten Klassen schränkst du
mögliche Fehlerquellen ein.
Wie wir bereits wissen, verbietet eine abstrakte Klasse das Instanzieren von Objekten. Wir haben
uns das bereits anhand des Beispiels der Basisklasse Auto und der Subklassen PKW und LKW
angesehen. Da es nur PKW- oder LKW-Objekte geben kann, wäre das Instanzieren von AutoObjekten sinnlos.
be
Abstrakte Klassen können noch einen weiteren Zweck erfüllen: das Vorschreiben von abstrakten Methoden, die in einer Subklassen zwingend zu implementieren sind.
Abstrakte Methoden
Beachte
ro
Das Schlüsselwort abstract ist nicht nur für Klassen, sondern auch für Methoden und Properties zulässig.
Abstrakte Methoden und abstrakte Properties haben keine Implementierung, sind
nur in abstrakten Klassen erlaubt und dürfen nicht private sein.
sep
L 9: Abstrakte Methoden vererben
Die Klasse Fahrzeug schreibt für alle Subklassen die Methode Transportieren vor, ohne
sie selbst zu implementieren.
// abstrakte Basisklasse Fahrzeug
abstract class Fahrzeug
{
protected double kostenProKm;
public abstract void Transportieren(int km);
}
In einer nicht abstrakten Klasse müssen alle
geerbten abstrakten
Methoden mit Hilfe von
override implementiert
werden.
Abstrakte Methode
// Subklasse Auto
class Auto : Fahrzeug
{
public override void Transportieren(int km)
{
// do something
}
}
Erbt eine abstrakte
Klasse abstrakte Methoden, müssen diese nicht
implementiert werden.
// abstrakte Subklasse Zweirad
abstract class Zweirad : Fahrzeug
{
// erbt die abstrakte Methode Transportieren(int km)
}
Die Klasse Fahrrad erbt
die abstrakte Methode
durch die Vererbungshierarchie und muss sie
implementieren.
82
Le
Eine abstrakte Methode
muss sich in einer
abstrakten Klasse befinden.
// Subklasse Fahrrad
class Fahrrad : Zweirad
{
public override void Transportieren(int km)
{
// do something
}
}
Softwareentwicklung
Lerneinheit 2: Vererbung
Wofür setze ich abstrakte Methoden ein?
Eine abstrakte Methode schreibt einer Subklasse die Implementierung der Methode vor. Eine nicht abstrakte Subklasse muss
alle geerbten abstrakten Methoden implementieren.
Im Gegensatz zu C++ unterstützt C# keine direkte Mehrfachvererbung. Eine Subklasse hat
genau eine Basisklasse. Interfaces stellen aber eine Alternative zur Mehrfachvererbung dar.
6 Interfaces
be
Vorschriften für Klassen
ro
Wir haben erfahren, dass wir mit Hilfe von Vererbung viel Zeit und Arbeit einsparen können,
indem wir Klassen in Subklassen erweitern bzw. verändern. Um die Notwendigkeit von Mehrfachvererbung zu verstehen, erweitern wir unser Fallbeispiel um die Klasse Bahn. Das Programm
soll berechnen, mit welchem Transportmittel die günstigsten Fahrtkosten erzielt werden. Wir erstellen zunächst die Klasse Bahn in gewohnter Art und Weise.
L 10: Klasse Bahn
Die Klasse Bahn beinhaltet die Eigenschaften preisProKm und transportkosten sowie die
Methode Transportieren.
// Klasse Bahn
class Bahn
{
private double transportkosten;
private double kostenProKm = 0.35;
sep
Das Fallbeispiel
Fuhrpark_Interface
findest du unter der
ID: 1184.
Le
public void Transportieren(int km)
{
transportkosten += km * kostenProKm;
}
}
Wenn wir nun das Fuhrpark-Array im Hauptprogramm um ein Bahn-Objekt erweitern, stoßen
wir unweigerlich auf ein Problem: Das Bahn-Objekt hat mit der Klasse Auto nichts zu tun und
lässt sich daher auch nicht in den Typ Auto casten!
Die Lösung unseres Problems ist das Interface IFahrzeug, das wir in alle Klassen vererben, die
wir zur Transportkostenberechnung verwenden, z.B. die Klassen Bahn, PKW und LKW.
L 11: Interface
Das Interface IFahrzeug implementiert die Methode Transportieren sowie die Properties
Kosten und Bezeichnung.
Das Fallbeispiel
Fuhrpark_Interface
findest du unter der
ID: 1184.
Ein Interface enthält
ausschließlich abstrakte
Methoden und Properties.
Softwareentwicklung
// Interface IFahrzeug
interface IFahrzeug
{
// Methode Transportieren
void Transportieren(int km);
// Properties
double Kosten { get; }
string Bezeichnung { get; }
}
Abstrakte Methode
Abstrakte Properties
83
2 Objektorientiertes Programmieren
Mr. What und
Ms. Check
Lernen
Üben
Sichern
Wissen
IFahrzeug
Auto
marke
kraftstoffvorrat
fahrtkosten
Transportieren()
Tanken()
Fahren()
PKW
Bahn
Diese Abbildung findest
du in der PowerPointPräsentation unter der
ID: 1184.
Transportieren()
vignette
achszahl
Fahren()
Transportieren()
Fahren()
Transportieren()
be
transportkosten
kostenProKm
LKW
Abb.: Interface zur Mehrfachvererbung
ro
Interfaces verwenden
1 Ein Interface legt Methoden und Properties ohne Implementierung fest.
Die Methode Transportieren() und die Get-Properties im Interface IFahrzeug aus dem
Lehrbeispiel L 10 enthalten keine Implementierungen – sie sind abstrakt.
2 Eine Klasse darf aus maximal einer Basisklasse und zusätzlich aus mehreren Interfaces abgeleitet werden.
sep
Die Klasse Bahn erbt z.B. nur vom Interface IFahrzeug. Die Klassen PKW und LKW erben
von der Klasse Auto und vom Inferface IFahrzeug.
3 Wenn eine Klasse von einem Interface erbt, muss sie alle Methoden und Properties aus dem Interface implementieren oder selbst abstrakt sein.
Beachte
Le
Die Klassen Bahn, PKW und LKW müssen die im Interface IFahrzeug festgelegte Methode
Transportieren() implementieren, falls nicht, müssten sie abstrakte Klassen sein.
Ein Objekt lässt sich in den Typ eines Interfaces casten, wenn es von einer Klasse instanziert wird, die das Interface implementiert.
Für das Array, das alle Transportmittelobjekte enthält, verwenden wir als Datentyp statt einer
Klasse nun das Interface IFahrzeug. Da alle Objekte des Arrays vom Interface ableiten, können
wir jedes Objekt in den Typ des Interfaces casten.
IFahrzeug
Transportieren()
PKW
Das Array ist vom
Typ des Interfaces
IFahrzeug und
enthält PKW-, LKWund Bahn-Objekte.
LKW
Bahn
Diese Abbildung findest
du in der PowerPointPräsentation unter der
ID: 1184.
84
Array
Abb.: Interface verwenden
Softwareentwicklung
Lerneinheit 2: Vererbung
L 12: Array vom Typ eines Interfaces
Das Array mit den Transportmitteln ist vom Typ des Interfaces IFahrzeug.
IFahrzeug[] transportmittel =
{
new Pkw("Mercedes", 7.5, 70, true),
new Lkw("Actros", 15.3, 250, 5),
new Pkw("VW Sprinter", 9.2, 80),
new Bahn()
};
2 Objektorientiertes Programmieren
Das Fallbeispiel
Fuhrpark_Interface
findest du unter der
ID: 1184.
ID: 1184
Was bedeutet gegen eine Klasse
bzw. gegen ein Interface programmieren?
Wenn du als Datentyp eine Klasse verwendest, programmierst
du gegen eine Klasse. Gegen ein Interface programmierst du,
wenn du ein Interface als Datentyp benutzt. Mit der zweiten
Methode bist du wesentlich flexibler, wenn du mehrere verschiedene Klassen verwendest, die nicht vererbbar sind.
In SbX findest du das Lehrbeispiel Fuhrpark unter Verwendung von Vererbung, Polymorphie und Interfaces.
Le
Üben
Übungsbeispiele
ro
Mr. What und
Ms. Check
Damit dieses Beispiel funktioniert, müssen auch die Klassen PKW und LKW die Methode
Transportieren() und die beiden Properties des Interfaces IFahrzeug implementieren.
sep
Beachte
be
foreach(IFahrzeug fahrzeug in transportmittel)
{
fahrzeug.Transportieren(200);
}
Ü 3:
Erstelle die Basisklasse Flugzeug mit den Eigenschaften Flugnummer, Reiseziel, Sitzplatzanzahl und der Anzahl der Reservierungen. Die Parameter für den Konstruktor sind Flugnummer, Reiseziel und Sitzplatzanzahl. Ein Standardkonstruktor ist nicht zulässig. Erstelle
die Methode Reservieren(), die die Anzahl der Reservierungen erhöht. Die Methode darf keine
Überbuchung eines Flugzeuges zulassen.
a) Erstelle die Subklassen Hubschrauber und Transportflugzeug.
b) Die Klasse Transportflugzeug erhält zusätzlich die Eigenschaft Transportgewicht.
c) Erstelle die Konstruktormethoden für die Subklassen. Das Transportgewicht ist bei einem
Transportflugzeug verpflichtend anzugeben.
Ü 4:
Erstelle zur nachfolgend abgebildeten Klasse Artikel die Subklassen Speise und Getränk.
a) Die Subklassen erben alle Eigenschaften der Basisklasse.
b) Ändere die Methode Verkaufen() in der Basisklasse in eine virtuelle Methode und berücksichtige das in den Subklassen.
Softwareentwicklung
85
Lernen
Üben
Sichern
Wissen
c) Die Methode Verkaufen() in den Subklassen berechnet den Nettoumsatz. Für Speisen beträgt der Umsatzsteuersatz 10 %, für Getränke 20 %.
d) Im Hauptprogramm sollen die Speisen und die Getränke in einem Array abgelegt werden.
Erstelle ein Array für eine Pizza Diabolo und ein Coca Cola. Wähle die Preise selbst aus.
e) Erstelle das Interface IArtikel mit der Methode Verkaufen() und den Get-Properties Bezeichnung und NettoUmsatz. Vererbe das Interface in die Klasse Artikel.
be
class Artikel
{
// Eigenschaften
private string bezeichnung;
private double bruttoPreis, nettoUmsatz;
private static byte[] ust = { 10, 20 };
ro
// Konstruktor
public Artikel(string bezeichnung, double bruttoPreis)
{
this.bezeichnung = bezeichnung;
this.bruttoPreis = bruttoPreis;
this.nettoUmsatz = 0;
}
sep
// Methode Verkaufen()
public void Verkaufen(int stk)
{
if (stk <= 0)
throw new Exception("Die Verkaufsmenge ist ungültig.");
else
{
// Nettoumsatz berechnen, aber
// Speise = 10 % bzw. Getränk = 20 % USt
// nettoUmsatz += bruttoPreis * stk / (1 + ust[?] / 100)
}
}
Le
// Properties
public Bezeichnung { get { return bezeichnung; } }
public NettoUmsatz { get { return nettoUmsatz; } }
}
Ü 5:
a) Erstelle das Interface IArtikel mit der Methode Verkaufen() und den Get-Properties Bezeichnung und NettoUmsatz. Vererbe das Interface in die Klasse Hotel.
b)Erstelle die neue Klasse Hotel und vererbe ihr das Interface IArtikel. Implementiere alle dadurch erforderlichen Methoden und Properties.
c) Erstelle die Eigenschaft Nächtigungspauschale in der Klasse Hotel.
d)Implementiere die Methode Nächtigung() mit dem Parameter AnzahlNächte und erhöhe
den Nettoumsatz um AnzahlNächte x Nächtigungspauschale. Das Nächtigungspauschale
ist bereits Netto.
e) Das Hotel bietet Zimmer mit Halbpension bzw. Zimmer/Frühstück an. Erstelle die Subklassen
Halbpension und Frühstück und ändere die Methode Nächtigung() in der Basisklasse in
eine virtuelle Methode. Die Methoden in den Subklassen erhöhen den Nettoumsatz zusätzlich um die Kosten für das Essen (Halbpension 18 EUR, Frühstück 6 EUR).
Zusätzlich zu diesen Übungen findest du in SbX eine Internetaufgabe.
ID: 1185
86
Softwareentwicklung
Lerneinheit 2: Vererbung
Sichern
Eine Basisklasse vererbt ihre Eigenschaften, Methoden und Properties an die Subklasse,
sofern die Zugriffsmodifizierer protected oder public verwendet werden.
Konstruktoren
wiederverwenden
Konstruktormethoden werden nicht vererbt, sondern müssen in der Subklasse neu implementiert werden. Die Konstruktormethode der Subklasse kann aber mit dem Schlüsselwort
base einen Basisklassenkonstruktor aufrufen.
Methoden
überschreiben
Eine Subklasse kann geerbte Methoden überschreiben und damit neu implementieren,
z.B. verändern oder erweitern. Die Methode der Basisklasse wird mit base.Methode() aufgerufen.
Polymorphie
Wird eine Methode in der Basisklasse als virtual deklariert, muss jede Subklasse diese Methode mit override neu implementieren.
Spätes Binden
Durch die Verwendung virtueller Methoden (Polymorphie) ist es möglich, Objekte vom Typ
einer Subklasse in den Typ der Basisklasse zu casten, z.B. in einem Array. Erst beim Ausführen der virtuellen Methode steht fest, welches Objekt die Methode aufgerufen hat und
welche Methode daher auszuführen ist.
Interface
Eine Klasse kann nur von einer Klasse erben, aber dafür von mehreren Interfaces. Ein
Interface enthält die Deklaration von Methoden und Properties, jedoch keine Implementierung. Wird ein Interface in eine Klasse vererbt, so muss die Klasse alle Methoden und
Properties des Interfaces implementieren.
sep
ro
be
Vererbung
Zusätzlich zu dieser Zusammenfassung findest du in SbX eine Bildschirmpräsentation.
ID: 1186
Le
Wissen
Wiederholungsfragen und -aufgaben
1.Erkläre die Begriffe Basis- und Subklasse!
2.Welche Bestandteile einer Klasse werden vererbt?
3.Wie kann eine Konstruktormethode der Basisklasse in einer Subklasse wiederverwendet
werden?
4.Welche Problematik tritt auf, wenn die Subklasse keinen Konstruktor implementiert, die
Basisklasse aber schon?
5.Erkläre die Unterschiede zwischen private, protected und public!
6.Welche Auswirkung hat das Schlüsselwort virtual auf die Verwendung von Methoden?
7.Erkläre das späte Binden (late Binding) im Rahmen der Polymorphie!
8.Beschreibe Unterschiede zwischen einem Interface und einer Klasse!
Softwareentwicklung
87
2 Objektorientiertes Programmieren
In dieser Lerneinheit haben wir die Grundlagen der Vererbung sowie die Verwendung
von Polymorphie und Mehrfachvererbung kennengelernt:
Lernen
Üben
Sichern
Wissen
9.Was bedeutet gegen eine Klasse bzw. gegen ein Interface programmieren?
10.Welche Konsequenzen hat das Einbinden eines Interfaces in eine Klasse?
11.Welche Vorteile bietet die Verwendung von Interfaces gegenüber Klassen?
Zusätzlich zu diesen Aufgaben findest du in SbX ein Quiz.
ID: 1187
Lerncheck
Ich kann jetzt …
be
w ... die Bestandteile einer Klasse in Subklassen vererben und Konstruktormethoden der Basisklasse wiederverwenden.
w ... virtuelle Methoden erstellen und in den Subklassen überschreiben.
w ... Polymorphie und spätes Binden verwenden.
w ... gegen Klassen und gegen Interfaces programmieren und meine Klassen durch Mehrfachvererbung flexibler gestalten.
Le
sep
ro
In der nächsten Lerneinheit beschäftigen wir uns mit speziellen Konzepten von .NET, wie z.B.
den generischen Typparametern (Generics), Indexern und Methodenzeigern (Delegates).
88
Softwareentwicklung
Lerneinheit 3: Weitere OOP-Konzepte
Lerneinheit 3
Weitere OOP-Konzepte
In dieser Lerneinheit lernen wir den Einsatz von generischen Typen für Collections
sowie das Konzept der Delegates kennen.
Wir beschäftigen uns mit
2 Objektorientiertes Programmieren
Alle SbX-Inhalte zu dieser Lerneinheit findest
du unter der ID: 1188.
be
● der Verwendung von Generics, Indexern und Interfaces sowie
● dem Aufruf von Funktionen mit Hilfe von Delegates.
Lernen
1 Generics
ro
Typsicherheit für Klassen
Generics sind ein neues Konzept in .NET 2.0 und werden als Basistechnologie sehr intensiv
im .NET-Framework eingesetzt. Wenn wir in Visual Studio 2005 ein neues Projekt erzeugen, egal
ob Konsolen- oder Windowsanwendung, erhalten wir automatisch den Namensraum System.
Collections.Generic eingebunden.
Der Typparameter T
wird als Stellvertreter
für den Datentyp verwendet.
Das Get-Property liefert
das ganze Array zurück.
Das Set-Property fügt
dem Array ein neues
Objekt hinzu.
Das Lehrbeispiel
GenericFlotte findest du
unter der ID: 1189.
Softwareentwicklung
L 1: Generische Klasse
Die generische Klasse Flotte speichert beliebige Datentypen in einem Array.
class Flotte<T>
{
private T[] fahrzeuge;
private int index;
Le
<T> ergänzt als generischer Typparameter
den Namen der Klasse.
sep
Im folgenden Lehrbeispiel erstellen wir die Klasse Flotte. Diese soll unterschiedliche Datentypen in einem Array speichern, z.B. Strings oder Fahrrad-Objekte. Der Vorteil generischer Klassen ist ihre universelle Einsatzfähigkeit.
public Flotte(int anzahl)
{
fahrzeuge = new T[anzahl];
index = -1;
}
public T[] Fahrzeuge { get { return fahrzeuge; } }
public T Neu
{
set
{
index++;
if (index < fahrzeuge.Length)
fahrzeuge[index] = value;
else
throw new Exception("Die Flotte ist voll.");
}
}
}
89
Lernen
Üben
Sichern
Wissen
class Fahrrad
{
private string marke, farbe;
public Fahrrad(string marke, string farbe)
{
this.marke = marke;
this.farbe = farbe;
}
public string Marke { get { return marke; } }
public string Farbe { get { return farbe; } }
}
be
// Hauptprogramm
Flotte<string> wien = new Flotte<string>(10);
wien.Neu = "BMW 320d";
wien.Neu = "Audi A4";
wien.Neu = "Opel Astra";
Flotte<Fahrrad> linz = new Flotte<Fahrrad>(5);
linz.Neu = new Fahrrad("KTM", "Silber");
linz.Neu = new Fahrrad("KTM", "Blau");
ro
Zur Verwendung der
generischen Klasse
Flotte wird bei der Objektinstanzierung der
Typparameter übergeben, z.B. ein String oder
eine andere Klasse.
sep
Console.WriteLine("Flotte Wien:");
foreach (string f in wien.Fahrzeuge)
{
if (f != null)
Console.WriteLine(f);
}
Console.WriteLine("\nFlotte Linz:");
foreach (Fahrrad f in linz.Fahrzeuge)
{
if (f != null)
Console.WriteLine(f.Marke + ", " + f.Farbe);
}
Le
Anstatt eines generischen Typparameters hätten wir in der Klasse Flotte auch mit dem allgemeinen Datentyp Object arbeiten können. Jedes Objekt, z.B. ein String oder ein Fahrrad-Objekt
leiten implizit von der Klasse Object ab und lassen sich daher nach Object casten. Ein solches
Object-Array würde jede Art von Datentyp erlauben, z.B. Autos, Motorräder und Fahrräder
innerhalb nur einer Flotte.
Durch die Verwendung von Generics gelingen hingegen typsichere Klassen, z.B. generische Collections. Unsere generischen Flotten-Arrays erlauben nur Objekte des gleichen Typs, z.B. entweder nur Autos oder nur Fahrräder.
1 Ein Generic ist ein generischer Typparameter, der für eine Klasse die Verwendung
eines bestimmten Datentyps vorschreibt.
Zur Verwendung der Klasse Flotte muss bei der Instanzierung eines Objektes ein Typparameter in spitzen Klammern angegeben werden, z.B. Flotte<Auto> berlin = new
Flotte<Auto>(100);
2 Der Datentyp für ein generisches Objekt wird bei der Instanzierung angegeben.
Ein Flotten-Objekt kann einen beliebigen Datentyp als Typparameter erhalten. Dadurch
erhalten wir universell einsetzbare sowie typsichere Flotten-Objekte, die z.B. nur Autos
oder nur Fahrräder speichern können.
90
Softwareentwicklung
Lerneinheit 3: Weitere OOP-Konzepte
Flotte<Auto> bregenz =
new Flotte<Auto>(4);
T = Auto
Flotte<T>
Flotte<Fahrrad> graz =
new Flotte<Fahrrad>(2);
2 Objektorientiertes Programmieren
T = Fahrrad
Abb.: Generische Klassen verwenden
Generische Collections
ro
Diese Abbildung findest
du in der PowerPointPräsentation unter der
ID: 1189.
be
Flotte<T>
sep
Statt eines Arrays soll eine Collection verwendet werden, wodurch wir beliebig viele Flottenobjekte speichern können. Im Kapitel 1 haben wir die ArrayList kennengelernt, die das Speichern beliebiger Typen erlaubt, denn in einer ArrayList werden Objekte vom Typ Object gespeichert. Eine ArrayList bietet daher keine Typsicherheit.
Seit .NET 2.0 gibt es zusätzlich die generische Klasse List<T> im Namensraum System.
Collections.Generic. Diese Klasse erlaubt die Angabe eines gewünschten Datentyps für die
Listenelemente. List<T> ist das generische Pendant zur nicht generischen ArrayList.
Das Lehrbeispiel zeigt die Realisierung des Hauptprogrammes aus L 1 mit einer genersichen
Liste. Die Klasse Flotte wird nicht mehr benötigt.
Die generische Liste
ersetzt die Klasse
Flotte<T> und bietet
die gleiche Funktionalität.
Le
L 2: Generische Liste
Die generische Liste List<T> speichert nur Objekte des angegebenen Typs.
// Hauptprogramm
List<string> wien = new List<string>();
wien.Add("BMW 320d");
wien.Add("Audi A4");
wien.Add("Opel Astra");
List<Fahrrad> linz = new List<Fahrrad>();
linz.Add(new Fahrrad("KTM", "Silber"));
linz.Add(new Fahrrad("KTM", "Blau"));
Console.WriteLine("Flotte Wien:");
foreach (string f in wien)
{
Console.WriteLine(f);
}
Console.WriteLine("\nFlotte Linz:");
foreach (Fahrrad f in linz)
{
Console.WriteLine(f.Marke + ", " + f.Farbe);
}
Softwareentwicklung
91
Lernen
Üben
Mr. What und
Ms. Check
Sichern
Wissen
Kann ich eine generische
Liste auch mit Wertetypen
verwenden?
Ja, eine generische Liste ermöglicht die Verwendung
aller Datentypen, z.B. int, bool, string, object usw.
2 Innere Klassen
Klassen kapseln
Lösung:
Die Klassen Motor
und Sitz sind innere
Klassen von Auto.
class Motor {..}
class Sitz {..}
class Auto
{
private Motor motor;
private List<Sitz> sitze;
}
ro
Verstoß gegen das
Prinzip der Kapselung:
Die Klassen Motor und
Sitz sind eine Komposition der Klasse Auto.
be
Objekte bestehen häufig aus anderen Objekten, z.B. besteht eine Mietwagenflotte aus Autos.
Ein Mietwagen-Objekt besteht wiederum aus einem Motor und Sitzgelegenheiten, um Personen
zu transportieren. Eine Klasse Auto, das aus einem Motorobjekt und einer Liste aus Sitzobjekten
besteht, könnten wir wie folgt erstellen:
sep
class Mietwagen : Auto {..}
Diese Lösung hat einen entscheidenden Nachteil – sie verstößt gegen das Prinzip der Kapselung! Die Klassen Motor und Sitz dürfen außerhalb der Klasse Auto nicht verwendbar sein, da
ein Motor oder ein Sitz ohne Auto nicht vermietet werden kann. Motor- und Sitzobjekte sollten
also ohne ein Auto nicht für sich alleine existieren dürfen.
Wenden wir das Prinzip der Kapselung auf die Klasse Auto an, müssen wir die Klassen Motor
und Sitz als private innere Klassen von Auto deklarieren.
Komposition =
Aggregation, bei der
die Teile vom Objekt
existenzabhängig sind.
Le
Aggregation =
Zusammensetzung
eines Objektes aus einer
Menge an Einzelteilen.
class Auto
{
private Motor motor;
private List<Sitz> sitze;
private class Motor {..}
private class Sitz {..}
}
Auto
Näheres zur Aggregation und zur Komposition erfährst du im
Kapitel zur UML.
Motor
hat
hat
Sitz
Komposition
Diese Abbildung findest
du in der PowerPointPräsentation unter der
ID: 1189.
92
Abb.: Innere Klassen
Softwareentwicklung
Lerneinheit 3: Weitere OOP-Konzepte
3 Indexer
Zugriff auf Listenelemente in einem Objekt
Die Klasse Flotte soll eine Liste von Auto-Objekten kapseln und über einen Indexer direkten
Zugriff auf die Listenelemente ermöglichen. Sehen wir uns den Programmcode dafür an:
Das Lehrbeispiel
Indexer findest du
unter der ID: 1189.
2 Objektorientiertes Programmieren
L 3: Indexer
Die Klasse Flotte enthält eine Liste von Autos und ermöglicht über den Objektnamen den
direkten Zugriff auf Listenelemente.
class Auto {..}
public Auto this[int index]
Auto-Objekt
{
get { return flotte[index]; }
set { flotte.Add(value); }
}
ro
Der Indexer wird als
Property mit dem
Namen this[] deklariert.
be
class Flotte
{
private List<Auto> flotte = new List<Auto>();
public int Count { get { return flotte.Count; } }
}
// Hauptprogramm
Flotte wien = new Flotte();
// Indexer verwenden
wien[0] = new Auto("Porsche", "Schwarz");
wien[1] = new Auto("Mercedes", "Rot");
sep
Indexer aufrufen
Beim Aufruf des Indexers mit wien[0] wird das erzeugte Auto-Objekt (z.B. Porsche oder
Mercedes) an das Property this[int index] vom Typ Auto übergeben. Die Eigenschaft value
des Set-Properties enthält das Auto-Objekt, das der Liste flotte hinzugefügt wird. Das GetProperty Count liefert die Anzahl der Auto-Objekte in einer Flotte.
Le
Der Indexer: this[]
Das Schlüsselwort this haben wir bereits kennengelernt, es referenziert das aktuelle Objekt. Im
Lehrbeispiel verweist this auf das Flottenobjekt wien. Der Aufruf von wien[0] ruft das Property
this[int index] auf und übergibt das erzeugte Auto-Objekt als Property-Value. Der Parameter index speichert den angegebenen Index (z.B. 0) und verweist auf das erste Listenelement.
Über das Get-Property von this[int index] wird ein Listen-Objekt ausgelesen.
Beachte
Mr. What und
Ms. Check
Softwareentwicklung
Der Aufruf eines Indexers sieht zwar wie der Aufruf eines Arrays aus, tatsächlich ist der
Indexer aber ein Property, das auf ein Array oder eine Collection zugreift.
Wofür kann ich einen Indexer sinnvoll einsetzen?
Mit einem Indexer kannst du direkt auf Arrays oder Collections
zugreifen, die in einem Objekt gekapselt sind. Das Objekt selbst
scheint die Liste zu sein und kann wie die Liste verwendet werden,
indem der Index des gewünschten Elements angegeben wird.
93
Lernen
Üben
Sichern
Wissen
Die Interfaces IEnumerable und IEnumerator
Damit die Klasse Flotte wie eine Liste verwendet werden kann, z.B. um damit durch eine foreach-Schleife zu iterieren, muss sie das Interface IEnumerable implementieren. Wie wir bereits wissen, schreibt die Implementierung eines
Interfaces die Implementierung der abstrakten Interface-Methoden vor. In unserem Fall ist
das die Methode GetEnumerator().
Interface-Smarttag
Der Smarttag des Interfaces ermöglicht die automatische Implementierung aller vorgeschriebenen Methoden.
Das Interface
IEnumerable schreibt
die Methode GetEnumerator() zur
Implementierung vor.
class Auto {..}
class Flotte : IEnumerable
{
private List<Auto> flotte = new List<Auto>();
public Auto this[int index]
{
get { return flotte[index]; }
set { flotte.Add(value); }
}
ro
Das Lehrbeispiel
Indexer findest du
unter der ID: 1189.
be
L 4: Implementierung des Interfaces IEnumerable
Die Klasse Flotte enthält eine Liste von Autos und ermöglicht über den Objektnamen den
direkten Zugriff auf Listenelemente.
public int Count { get { return flotte.Count; } }
Das Interface
IEnumerator schreibt
die Methoden für
die Klasse FlottenEnumerator vor.
sep
Die Implementierung
der Klasse FlottenEnumerator erfolgt als
innere Klasse.
public IEnumerator GetEnumerator()
{
return (IEnumerator)new FlottenEnumerator(this);
}
private class FlottenEnumerator : IEnumerator
{
private int index = -1;
private Flotte flotte;
public FlottenEnumerator(Flotte flotte)
{
this.flotte = flotte;
}
Le
Die Methode GetEnumerator() liefert ein
FlottenEnumeratorObjekt vom Typ des
Interfaces IEnumerator
zurück.
public object Current
{
get { return flotte[index]; }
}
public bool MoveNext()
{
index++;
if (index < flotte.Count)
return true; // Ende noch nicht überschritten!
else
return false; // Ende überschritten!
}
public void Reset()
{
index = -1;
}
}
}
94
Softwareentwicklung
Lerneinheit 3: Weitere OOP-Konzepte
4 Delegates und Events
Callbacks
Ein Delegate-Objekt kapselt den Verweis auf eine oder mehrere Methoden einer Klasse.
Mit Delegates können Callbacks (Rückrufe) und Events (Ereignisse) programmiert werden.
Die Methoden Fahren
und Fliegen in der
Klasse Transport werden durch den Callback
aufgerufen.
Delegate deklarieren
class Fahrzeug
{
public delegate void Transport(int distanz);
public void Transportieren(Transport trans)
{
if (trans != null)
Methodenparameter ist
trans(200);
das Delegate-Objekt
}
}
Callback
class Transport
{
public static void Fahren(int km)
{
Console.WriteLine("Fahre " + km + " km.");
}
public static void Fliegen(int flugmeilen)
{
Console.WriteLine("Fliege " + flugmeilen + " km.");
}
}
Le
// Hauptprogramm
Fahrzeug auto = new Fahrzeug();
Fahrzeug flugzeug = new Fahrzeug();
Das Delegate-Objekt
kapselt den Zeiger auf
die aufzurufende
Methode.
2 Objektorientiertes Programmieren
Die Methode Transportieren führt den Callback mit Hilfe des Delegate-Objektes durch.
be
Mit dem Schlüsselwort
delegate wird ein
Delegate deklariert.
L 5: Callbacks verwenden
Die Klasse Fahrzeug holt sich über einen Callback die benötigte Methode aus der Klasse
Transport.
ro
Das Lehrbeispiel
Delegate findest du
unter der ID: 1189.
Ein Delegate ist ein Objekt, das einen Zeiger auf eine Objektmethode beschreibt.
sep
Beachte
Delegate-Objekt instanzieren
Fahrzeug.Transport autoTrans =
new Fahrzeug.Transport(Transport.Fahren);
Fahrzeug.Transport flugzeugTrans =
new Fahrzeug.Transport(Transport.Fliegen);
auto.Transportieren(autoTrans);
flugzeug.Transportieren(flugzeugTrans);
Methodenaufruf mit DelegateObjekt als Parameter
1 Bei der Instanzierung des Delegate-Objektes wird die Zielmethode festgelegt.
Methodensignatur =
Rückgabetyp und Typen
der Parameter.
Das Delegate-Objekt beschreibt einen Zeiger auf die aufzurufende Methode. Die Methodensignaturen des Delegates sowie der Zielmethode müssen übereinstimmen.
2 Der Methodenaufruf erfolgt durch Übergabe des Delegate-Objektes.
Die Methode Transportieren der Klasse Fahrzeug weiß nicht, um welches Fahrzeug es sich
handelt. Die aufzurufende Zielmethode ist im Delegate-Objekt gekapselt. Wenn ein Delegate-Objekt vorhanden ist, erfolgt der Callback unter Ausführung des Delegates.
Softwareentwicklung
95
Lernen
Üben
Sichern
Wissen
Ereignisse (Events)
Die Ereignissteuerung, z.B. von Windowsprogrammen, basiert in C# auf Delegates. Das
Event verwendet ein Delegate zum Callback-Aufruf der Ereignisprozedur. Im folgenden
Lehrbeispiel reagiert die Ereignisprozedur reagiereAufKlingeln auf das Ereignis Klingeln,
wenn die Weckzeit erreicht ist.
L 6: Events verwenden
Die Klassen Wecker und Wecken kommunizieren über das Ereignis Klingeln.
delegate void WeckerEventHandler(DateTime uhrzeit);
// Klasse, die das Event auslöst
Delegate und Event
class Wecker
deklarieren
{
public event WeckerEventHandler Klingeln;
private DateTime weckzeit, uhrzeit; // Eigenschaften
public Wecker(DateTime weckzeit) // Konstruktor
{
this.weckzeit = weckzeit;
}
be
Der Delegate kapselt
den Aufruf des Eventhandlers reagiereAufKlingeln in der Klasse
Wecken.
Das Wecker-Objekt
registriert den
Eventhandler.
Das Lehrbeispiel
Events findest du unter
der ID: 1189.
96
// Klasse, die auf das Event reagiert
class Wecken
{
public Wecken(Wecker wecker) // Konstruktor
{
Eventhandler registrieren
wecker.Klingeln +=
new WeckerEventHandler(reagiereAufKlingeln);
}
private void reagiereAufKlingeln(DateTime uhrzeit)
{
Eventhandler
Console.WriteLine("Aufstehen!!!");
}
}
Le
Das Event Klingeln ruft
über den Delegate die
Ereignisprozedur auf.
sep
ro
public DateTime Uhrzeit // Property
{
get { return uhrzeit; }
set
{
uhrzeit = value;
if (uhrzeit.Hour == weckzeit.Hour
&& uhrzeit.Minute == weckzeit.Minute
&& uhrzeit.Second == weckzeit.Second)
{
Klingeln(uhrzeit);
Event auslösen
}
}
}
}
// Hauptprogramm
Wecker wecker = new Wecker(Convert.ToDateTime("6:30:00"));
Wecken wecken = new Wecken(wecker);
wecker.Uhrzeit = Convert.ToDateTime("6:29:55");
for (int i = 0; i <= 10; i++)
{
wecker.Uhrzeit = wecker.Uhrzeit.AddSeconds(1);
Console.WriteLine("Es ist jetzt: " + wecker.Uhrzeit);
}
Softwareentwicklung
Lerneinheit 3: Weitere OOP-Konzepte
1 Das Weckerobjekt wecker registriert den Eventhandler reagiereAufKlingeln für
das Event Klingeln.
Der Aufruf von Klingeln führt über den Delegate WeckerEventHandler zur Ereignisprozedur. Die Klasse Wecker kommuniziert über das Ereignis Klingeln mit der Klasse Wecken.
Das Prinzip der Kapselung wird auch für Nachrichten zwischen Objekten angewendet.
Wie funktionieren Ereignisse
in der Sprache Java?
In Java gibt es keine Delegates wie in C#, daher werden Ereignisse
dort als Objekte dargestellt. Im Anhang findest du eine Darstellung
einiger Unterschiede zwischen C# und Java.
ro
be
Mr. What und
Ms. Check
Üben
Ü 1:
Erstelle zu den folgenden Aufgaben die Deklarationen in C#:
sep
Übungsbeispiele
a) Erstelle eine generische Collection (Liste) für bool-Werte.
b) Erstelle eine Klasse mit den Eigenschaften km und reichweite, wobei die Datentypen beider
Eigenschaften generisch sind.
Ü 2:
Die Klasse Unterricht soll eine typsichere generische Liste enthalten. Der Unterricht darf nur für
Schüler oder für SeminarTeilnehmer stattfinden. Erstelle die inneren Klassen.
Le
class Unterricht
{
public ArrayList = new ArrayList();
}
class Lernender
{
public int jahrgang;
public string name;
}
class Schüler : Lernender
{
}
class SeminarTeilnehmer : Lernender
{
}
Softwareentwicklung
97
2 Objektorientiertes Programmieren
2 Da die Ereignisprozedur in der Klasse Wecken gekapselt ist (private), reagiert sie
ausschließlich auf das Auftreten des Ereignisses.
Lernen
Üben
Sichern
Wissen
Ü 3:
Erstelle die Klasse Orchester mit einer generischen Liste zum Speichern der verschiedenen Musikinstrumente, z.B. Flöte, Chello, Posaune usw. Alle Musikinstrumente implementieren das Interface IInstrument. Erstelle in der Klasse Orchester einen Indexer für den direkten Zugriff auf
die Instrumentenliste.

Ü 4:
Verwende die Klassen aus Ü 3 und ergänze die Klasse Konzert. Erstelle ein Delegate für das
Spielen eines Konzertes. Am Konzert sind alle Instrumente beteiligt. Verwalte die Instrumente in
einer generischen Liste vom Typ des Interfaces.
Zusätzlich zu diesen Übungen findest du in SbX eine Internetaufgabe.
be
ID: 1190
Sichern
ro
In dieser Lerneinheit haben wir weitere objektorientierte Konzepte, wie generische
Typparameter, innere Klassen, Indexer und Delegates, kennengelernt:
Ein Generic ist ein Typparameter für eine Klasse oder eine Methode um typsichere Klassen
und Methodenaufrufe programmieren zu können. Ein Beispiel für einen häufig verwendeten
Generic ist die genersiche Collection List<T> aus dem Namensraum System.Collections.
Generic.
Innere Klasse
Mit Hilfe von inneren Klassen lassen sich die Bestandteile von Klassen in weiteren Klassen
integrieren, ohne gegen das Prinzip der Kapselung zu verstoßen.
Indexer
Der Indexer this[] ermöglicht den Zugriff auf Listenelemente einer Eigenschaft in einer
Klasse über ein Property. Die Instanz der Klasse wird dabei wie eine Liste, z.B. ein Array oder
eine Collection, behandelt. Die Werte der Liste werden über einen Index angesprochen.
IEnumerable
Durch die Implementierung des Interfaces IEnumerable kann eine Klasse wie eine Liste
verwendet werden, z.B. mit einer foreach-Schleife.
Delegate
Ein Delegate ist ein Zeiger auf eine Methode. Delegates ermöglichen Callback-Aufrufe von
Methoden in anderen Klassen und stellen die Grundlage für die Eventprogrammierung in
C# dar.
Callback
Als Callback wird der Aufruf einer Methode in einer anderen Klasse bezeichnet. Callbacks
ermöglichen die Übermittlung von Nachrichten zwischen verschiedenen Objekten.
Event
Die Programmierung von Ereignissen funktioniert in C# über Delegates. Wenn ein Objekt
ein bestimmtes Ereignis auslösen möchte, muss der entsprechende Eventhandler abonniert
werden.
Le
sep
Generic
Zusätzlich zu dieser Zusammenfassung findest du in SbX eine Bildschirmpräsentation.
ID: 1191
98
Softwareentwicklung
Lerneinheit 3: Weitere OOP-Konzepte
Wissen
Wiederholungsfragen und -aufgaben
2.Welche Bestandteile einer Klasse werden vererbt?
3.Wie kann eine Konstruktormethode der Basisklasse in einer Subklasse wiederverwendet
werden?
be
4.Welche Problematik tritt auf, wenn die Subklasse keinen Konstruktor implementiert, die
Basisklasse aber schon?
5.Erkläre die Unterschiede zwischen private, protected und public!
6.Welche Auswirkung hat das Schlüsselwort virtual auf die Verwendung von Methoden?
7.Erkläre das späte Binden (late Binding) im Rahmen der Polymorphie!
ro
8.Beschreibe Unterschiede zwischen einem Interface und einer Klasse!
9.Was bedeutet gegen eine Klasse bzw. gegen ein Interface programmieren?
10.Welche Konsequenzen hat das Einbinden eines Interfaces in eine Klasse?
sep
11.Welche Vorteile bietet die Verwendung von Interfaces gegenüber Klassen?
Zusätzlich zu diesen Aufgaben findest du in SbX ein Quiz.
ID: 1192
Lerncheck
Ich kann jetzt …
Le
w ... die Bestandteile einer Klasse in Subklassen vererben und Konstruktormethoden der Basisklasse wiederverwenden.
w ... virtuelle Methoden erstellen und in den Subklassen überschreiben.
w ... Polymorphie und spätes Binden verwenden.
w ... gegen Klassen und gegen Interfaces programmieren und meine Klassen durch Mehrfachvererbung flexibler gestalten.
In der nächsten Lerneinheit beschäftigen wir uns mit ADO.NET und der Verwendung von Dateien und Datenbanken zum Lesen und Speichern von Daten.
Softwareentwicklung
99
2 Objektorientiertes Programmieren
1.Erkläre die Begriffe Basis- und Subklasse!
Lernen
Üben
Sichern
Wissen
Lerneinheit 4
Datenspeicherung
Alle SbX-Inhalte zu dieser Lerneinheit findest
du unter der ID: 1193.
In dieser Lerneinheit lernen wir, wie wir Objektdaten in einer Datei abspeichern und
aus einer Datei einlesen können. Für den Dateizugriff verwenden wir Textdateien
im CSV-Format, XML-Dateien und relationale Datenbanken.
In einem immer komplexer werdenden Lehrbeispiel beschäftigen wir uns mit
Lernen
Tier = Schicht;
häufig wird auch der
Begriff Layer verwendet.
Three-Tier-Architecture
ro
1 Drei-Schichten-Architektur
be
● dem Dateizugriff auf Textdateien mittels StreamReader und StreamWriter,
● der XML-Serialisierung von Objekten sowie
● dem Zugriff auf eine Access- bzw. SQL-Server-Datenbank.
In den Beispielen des ersten Kapitels befand sich die Programmlogik, wie z.B. eine Berechnung,
direkt im Formular der Windows-Anwendung.
sep
Im diesem Kapitel haben wir die Programmlogik in verschiedene Klassen eingekapselt und
dadurch die Windows-Formulare entlastet. Die aus den Logikklassen abgeleiteten Objekte achten auf die Korrektheit der enthaltenen Daten und erlauben keine unzulässigen Operationen
(Methoden).
In vielen Programmen werden die Präsentations- und die Logikschicht durch eine Datenschicht
erweitert. Diese ist für die dauerhafte Speicherung der Objektdaten verantwortlich und besteht im einfachsten Fall aus einer Textdatei.
Middle Tier:
Business-Logik, z.B.
Klassen für die Objektinstanzierung.
Data Tier:
Datenspeicherung, z.B.
Textdatei oder Datenbank.
Drei-Schichten-Architektur
Le
Presentation Tier:
Benutzerschnittstelle,
z.B. WinForms oder
WebForms.
Präsentationsschicht
Logikschicht
Diese Abbildung findest
du in der PowerPointPräsentation unter der
ID: 1194.
Beachte
100
Abb.: Drei-Schichten-Architektur
Datenschicht
Zur Modellierung der Logikschicht werden in der Praxis verschiedene Diagramme der Unified Modelling Language (UML) verwendet, z.B. ein Use-Case-Diagramm und ein Klassendiagramm. Mit UML beschäftigst du dich im Kapitel 3.
Softwareentwicklung
Lerneinheit 4: Datenspeicherung
Dreischichtige Anwendungen
1 Die Präsentationsschicht (Presentation Tier) umfasst die Benutzerschnittstelle.
Als Benutzerschnittstellen kommen Windows-Formulare, WebForms und Konsolenanwendungen in Frage. Zur Benutzerschnittstelle gehören die Navigation, die Darstellung von Eingabemasken, die Eingabeüberprüfung (Validitätsprüfung) und die Ausgabe von Berichten.
Bei der Geschäftslogik gilt der Grundsatz der Datenkapselung. Daten und Programmcodes
werden in Klassen bzw. davon abgeleiteten Objekten verwaltet. Klassen und Objekte sind für
ihre korrekte Funktion und ihre korrekten Daten eigenverantwortlich.
persistent = dauerhaft
3 Die Datenschicht (Data Tier) speichert die Daten der Objekte persistent ab.
Welchen Vorteil hat die Verwendung einer Drei-Schichten-Architektur?
Alle drei Schichten sind voneinander völlig unabhängig. So kannst
du die Geschäftslogik und die Datenschicht für Windows- und WebAnwendungen verwenden, ohne daran etwas verändern zu müssen.
ro
Mr. What und
Ms. Check
be
Damit die Daten der Objekte auch nach dem Schließen des Anwenderprogrammes bereitgestellt werden können, müssen diese dauerhaft gespeichert werden, z.B. in einer Textdatei, in
einer XML-Datei oder in einer relationalen Datenbank.
sep
Die Datenschicht besteht im einfachsten Fall aus einer Textdatei, die mit Hilfe entsprechender
.NET-Klassen erstellt und gelesen werden kann. Bei der Verwendung dieser Methoden achten
wir darauf, dass wir die Geschäftslogik von der Datenzugriffslogik abgrenzen. Wenn wir
später z.B. statt auf Text- auf XML-Dateien oder eine Datenbank zugreifen möchten, ist diese
Veränderung einfach und rasch durchführbar.
2 Textdateien
Die Klassen StreamReader und StreamWriter
Le
Das .NET-Framework bietet im Namensraum System.IO die Klassen StreamReader und
StreamWriter für den Zugriff auf Textdateien an.
CSV = comma
separated value
Diese Abbildung findest
du in der PowerPointPräsentation unter der
ID: 1194.
Softwareentwicklung
CSV-Datei
Abb.: Dateizugriff mit der Klasse StreamReader
101
2 Objektorientiertes Programmieren
2 Die Geschäftslogik (Business Logic) wird in Klassen eingekapselt.
Die Collection fz dient
vorübergehend als Container für die Fahrzeugobjekte.
Bei Pfadangaben stellen
wir einem String einen
Klammeraffen vor, z.B.
string pfad = @".\";
Das StreamReader-Objekt r öffnet die Datei
Fuhrpark.csv für den
Lesezugriff.
Die private Methode
GetFahrzeug() liefert
ein fertiges Objekt vom
Interfacetyp IFahrzeug.
Um die Polymorphie
nutzen zu können,
werden alle Fahrzeugobjekte von der
Collection in das Array
fahrzeug kopiert.
Die Methode Split() erzeugt ein Array mit den
Feldern der Zeile. Als
Trennzeichen wird ein
Strichpunkt festgelegt.
Die Hilfsmethode
GetFahrzeug() erhält
die aus der Textdatei
eingelesene Zeile als
Parameter übergeben
und erzeugt daraus ein
PKW- bzw. LKW-Objekt,
das an die Methode
Fahrzeugdatei_Lesen()
zurückgegeben wird.
102
Das folgende Lehrbeispiel zeigt die Erweiterung des Fuhrparkbeispieles um die Klasse Datenzugriff mit der Methode Fahrzeugdatei_Lesen().
L 1:
Die Klasse Datenzugriff kapselt die statische Methode Fahrzeugdatei_Lesen().
using System.Collections;
using System.IO;
Die Methode verweist auf das Array
fahrzeug aus dem aufrufenden Code.
class Datenzugriff
{
public static void Fahrzeugdatei_Lesen(ref IFahrzeug[] fahrzeug)
{
ArrayList fz = new ArrayList();
fz.Add(new Bahn());
Referenztypparameter
string pfad = @".\";
string dateiname = "Fuhrpark.csv";
string zeile;
be
Zur Verwendung der
Klasse StreamReader
wird der Namensraum
System.IO eingebunden.
Wissen
StreamReader r = new StreamReader(pfad + dateiname);
while ((zeile = r.ReadLine()) != null)
{
fz.Add(GetFahrzeug(zeile));
}
r.Close();
ro
Das Fallbeispiel Fuhrpark_CSV findest du
unter der ID: 1194.
Sichern
// Arraylist in das Array fahrzeug kopieren
fahrzeug = new IFahrzeug[fz.Count];
fz.CopyTo(fahrzeug);
}
sep
Üben
// Hilfsmethode erzeugt ein Pkw-/Lkw-Objekt
// aus dem übergebenen CSV-String
private static IFahrzeug GetFahrzeug(string zeile)
{
IFahrzeug auto;
Motor motor;
string[] felder = zeile.Split(';');
if (felder[0] == "Pkw")
{
if (felder[5] == "Benzin")
motor = Motor.Benzin;
else
motor = Motor.Diesel;
Le
Lernen
auto = new Pkw(felder[1], felder[2],
Convert.ToDouble(felder[3]),
Convert.ToDouble(felder[4]),
motor, Convert.ToBoolean(felder[6]));
}
else
{
auto = new Lkw(felder[1], felder[2],
Convert.ToDouble(felder[3]),
Convert.ToDouble(felder[4]),
Convert.ToByte(felder[5]));
}
return auto;
}
}
Softwareentwicklung
Lerneinheit 4: Datenspeicherung
Die Klasse Datenzugriff verbindet die Geschäftslogik, das Array fahrzeug, mit der Datenschicht, der Textdatei Fuhrpark.csv.
Abb.: Dateizugriff mit der Klasse StreamReader
sep
Diese Abbildung findest
du in der PowerPointPräsentation unter der
ID: 1194.
ro
be
2 Objektorientiertes Programmieren
Die statische Methode Fahrzeugdatei_Lesen() erhält als Parameter einen Verweis auf das
Array fahrzeug des aufrufenden Codes, der Geschäftslogik. Durch den Verweistypparameter
greift die Methode auf das Array der Geschäftslogik durch und erstellt darin ein neues Array mit
den aus der Textdatei eingelesenen Fahrzeugobjekten.
Ü 1:
Erstelle die statische Methode GetFahrzeuge() in der Klasse Datenzugriff. Die Methode
hat keine Parameter und der Rückgabewert ist ein Array vom Typ IFahrzeug.
Der Methodenaufruf von GetFahrzeuge() lautet im Hauptprogramm wie folgt:
Le
IFahrzeug[] fahrzeug;
...
fahrzeug = Datenzugriff.GetFahrzeuge();
Das folgende Lehrbeispiel L 2 demonstriert das Speichern von Textdateien sowie das Öffnen
der geschriebenen Datei mit einer Applikation, z.B. Excel für CSV-Dateien.
L 2:
Die Klasse Datenzugriff wird um die Methode Transportkostendatei_Schreiben() erweitert.
Das Fallbeispiel Fuhrpark_CSV findest du
unter der ID: 1194.
Mit dem StreamWriter-Objekt w wird
eine neue Datei erstellt.
false = Neue Datei
true = Datei ergänzen
public static void
Transportkostendatei_Schreiben(ref IFahrzeug[] fahrzeug)
{
string pfad = @".\";
string dateiname = "Transportkosten.csv";
string zeile;
StreamWriter w = new StreamWriter(pfad + dateiname,
false, Encoding.Default);
Das Encoding legt den
Zeichensatz für die
Textdatei fest.
Softwareentwicklung
103
In der Variablen zeile
wird der Ausgabestring
für die Textdatei zusammengebaut.
Die Methode WriteLine() schreibt die Zeile
in die Textdatei.
Startet ein Programm
zur Bearbeitung von
CSV-Dateien, z.B. Excel.
Hinweis
Wissen
foreach (IFahrzeug fz in fahrzeug)
{
if (fz is Pkw)
zeile = "Pkw;";
else if (fz is Lkw)
zeile = "Lkw;";
else
zeile = "Bahn;";
zeile += fz.Bezeichnung + ";"
+ fz.Kosten.ToString("C");
w.WriteLine(zeile);
}
w.Close();
// Datei mit verknüpftem Programm öffnen, z.B. Excel
System.Diagnostics.Process.Start(pfad + dateiname);
}
Der Aufruf der Textdatei sollte idealerweise in der Präsentationsschicht erfolgen, um die
Datenschicht unabhängig zu machen.
Kann ich mit StreamReader
auch Bilder einlesen?
Nein, zum Einlesen von Binärdateien gibt es die Klasse BinaryReader. Mit der Methode PeekChar() kannst du Zeichen für Zeichen
aus einer Binärdatei, z.B. einem Bitmap, einlesen. Wenn das Dateiende erreicht ist, liefert PeekChar() den Wert –1.
sep
Mr. What und
Ms. Check
Sichern
be
Üben
ro
Lernen
Le
Neben dem Zugriff auf Textdateien ist es häufig erforderlich, den Inhalt von Verzeichnissen zu
verarbeiten, neue Verzeichnisse anzulegen oder bestehende zu löschen. Auch für die Verarbeitung von Dateien werden oft bestimmte Informationen benötigt. Für diese Operationen bietet
das Framework einige Klassen an.
3 Dateisystem-Operationen
Arbeiten mit Verzeichnissen und Dateien
Das .NET-Framework stellt zur Bearbeitung von Verzeichnissen und Dateien folgende Klassen zur Verfügung:
Klasse
Aufruf
über
Methode
Beschreibung
Directory
Klasse
CreateDirectory(pfad)
Erstellt ein Verzeichnis im angegebenen
Pfad.
Delete(pfad, true)
Löscht ein Verzeichnis mit allen Unterverzeichnissen und Dateien im angegebenen Pfad.
Move(pfad1, pfad2)
Verschiebt das Verzeichnis pfad1 an die
Stelle von pfad2 und ändert ggf. den
Namen.
SetCurrentDirectory(pfad) Legt das aktuelle Arbeitsverzeichnis fest.
GetCurrentDirectory()
104
Ermittelt das aktuelle Arbeitsverzeichnis.
Softwareentwicklung
Aufruf
über
Methode
Beschreibung
DirectoryInfo
Objekt
GetDirectories()
Liefert alle Unterverzeichnisse in einem
Array zurück.
GetFiles()
Liefert alle Dateien in einem Array zurück.
Copy(file1, file2)
Kopiert die Datei file1 nach file2.
Move(file1, file2)
Verschiebt die Datei file1 nach file2;
wird auch zum Umbenennen verwendet.
GetCreationTime(file)
Liefert Datum und Uhrzeit der Erstellung.
GetLastAccessTime(file)
Liefert Datum und Uhrzeit des letzten
Zugriffs.
File
Klasse
GetAttributes(file)
Exists(file)
Liefert die Dateiattribute, z.B. Archive,
Hidden, ReadOnly, Compressed, Directory etc., als Wert zurück.
Liefert true, falls die Datei existiert.
Die Klassen Directory und File enthalten statische Methoden, die Klasse DirectoryInfo
hingegen nicht-statische, d.h. dass der Methodenaufruf über ein instanziertes Objekt
erfolgt.
ro
Beachte
be
Klasse
sep
Das folgende Lehrbeispiel demonstriert die Verwendung der in der Tabelle angeführten Operationen.
L 3:
Verschiedene Operationen für die Bearbeitung von Verzeichnissen und Dateien:
using System.IO;
// Verzeichnis erstellen
Directory.CreateDirectory(@"c:\meinOrdner");
Le
// Verzeichnis verschieben und umbenennen
Directory.Move(@"c:\meinOrdner", @"d:\deinOrdner");
// Verzeichnis mit allen Inhalten löschen
Directory.Delete(@"c:\oldstuff");
// Arbeitsverzeichnis festlegen
Directory.SetCurrentDirectory(@"d:\deinOrdner");
// Arbeitsverzeichnis ermitteln
string pfad = Directory.GetCurrentDirectory();
// DirectoryInfo verwendet nicht-statische Methoden
// –> Objekt dirObj instanzieren
DirectoryInfo dirObj = new DirectoryInfo(@"c:\windows");
Die Eigenschaft Name
enthält den Namen
des Verzeichnisses
bzw. der Datei,
z.B. subdirs[i].Name
oder files[i].Name.
Softwareentwicklung
// Unterverzeichnisse ermitteln
DirectoryInfo[] subdirs = dirObj.GetDirectories();
// Dateien eines Verzeichnisses ermitteln
FileInfo[] files = dirObj.GetFiles();
105
2 Objektorientiertes Programmieren
Lerneinheit 4: Datenspeicherung
Lernen
Üben
Sichern
Wissen
// Datei kopieren
File.Copy(@"c:\daten.txt", @"d:\deinOrdner\daten.txt");
// Datei umbenennen (beide Pfade sind ident)
File.Move(@"d:\deinOrdner\daten.txt", @"d:\deinOrdner\autos.csv");
// Datei verschieben und umbenennen
File.Move(@"d:\deinOrdner\autos.csv", @"e:\sicherung.csv");
be
Gibt es auch Klassen, um auf
Dateien und Ordner zugreifen zu können?
Mit der Klasse DriveInfo kannst du die Laufwerke, mit DirectoryInfo
Ordner und mit FileInfo Dateien anzeigen lassen. Die Sicherheitseinstellungen von Ordnern und Dateien (ACL) kannst du über den
Namespace System.Security.AccessControl verändern bzw. auslesen.
sep
Mr. What und
Ms. Check
ro
Zur Ermittlung des
Dateiattributes
ReadOnly wird eine
bitweise Oder-Verknüpfung durchgeführt.
// Dateiattribute ermitteln
Directory.SetCurrentDirectory(@"d:\deinOrdner");
if (File.Exists("autos.csv"))
{
label1.Text = "Erstellungsdatum: " +
File.GetCreationTime("autos.csv").ToString();
FileAttributes a = File.GetAttributes("autos.csv");
if (a == (a | FileAttributes.ReadOnly))
MessageBox.Show("Die Datei ist schreibgeschützt.");
}
else
label1.Text = "File existiert nicht.";
Ein großer Nachteil bei der Verwendung von Textdateien zur Datenspeicherung besteht darin,
dass der Aufbau der Daten in der Textdatei fest vorgegeben ist. Mit Hilfe der Extensible Markup Language (XML) lassen sich Textdateien erstellen, die ihre Datenstruktur selbst beschreiben
und gleichzeitig die Daten enthalten.
Le
4 XML-Serialisierung
Objekte speichern
Serialisierung ist das Abspeichern bzw. Laden von Objekten auf ein Speichermedium, wie
z.B. eine Festplatte. Wie wir be<?xml version="1.0"?>
reits gesehen haben, ist die Se<ArrayOfAnyType
rialisierung mittels Textdateien
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
keine ideale Lösung, denn die
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<anyType xsi:type="XmlAuto">
Inhalte der Textdatei sind starr.
<Bezeichnung>Bahn</Bezeichnung>
Der Aufbau der Datei muss
<Kosten>350</Kosten>
immer gleich sein.
</anyType>
Der Aufbau der Daten
ist Bestandteil einer
XML-Datei.
<anyType xsi:type="XmlAuto">
<Bezeichnung>E 230, W-1001</Bezeichnung>
<Kosten>822.6</Kosten>
</anyType>
<anyType xsi:type="XmlAuto">
<Bezeichnung>VW Sprinter, W-1003</Bezeichnung>
<Kosten>920</Kosten>
</anyType>
</ArrayOfAnyType>
Eine XML-Datei enthält die Objektdaten in Form einer Baumstruktur und beschreibt den Typ
der Daten, z.B. die Klasse.
Abb.: XML-Darstellung von Fahrzeug-Objekten
106
Softwareentwicklung
Lerneinheit 4: Datenspeicherung
Extensible Markup Language
Die Extensible Markup Language (XML) dient zur strukturierten Speicherung und zum
Austausch von Daten. XML-Dateien sind logisch als Baumstruktur aufgebaut. Die Hierarchie für
den Aufbau der Daten ist in der XML-Datei enthalten (Schema).
Aufbau von XML-Dateien
XML = Extensible
Markup Language
1 Eine XML-Datei speichert Daten in Form einer Baumstruktur.
Die Felder der Tabelle T_Schueler werden als Tags dargestellt und beinhalten die Daten.
XSD = XML-SchemaDefinition
XSL = XML-Style-Sheet
be
2 Das XML-Schema legt die Struktur der XML-Datei fest.
Die XML-Schema-Definition (XSD) kann Bestandteil der XML-Datei sein oder importiert werden. In der Beispieldatei wird ein Standard-XSD des W3C verwendet.
3 Ein XML-Style-Sheet legt das Layout der XML-Datei fest.
ro
XML-Style-Sheet (XSL) ist ein Sprachstandard zur Formatierung von XML-Seiten. So könnte
z.B. eine XML-Datei auf einem Ausdruck anders aussehen als bei der Anzeige am PC.
XML ist ein wesentlicher Bestandteil des .NET-Frameworks. Es bietet nicht nur mächtige
Klassen zur Verarbeitung von XML-Dateien an, sondern nutzt auch selbst XML intensiv als Datenformat. Auch Visual Studio 2005 verwendet XML innerhalb von Projekten, z.B. liegen alle
Dateien mit den Endungen .csproj, .resx und .settings im XML-Format vor.
sep
Objekte serialisieren
Um Objekte in eine XML-Datei mittels XML-Serialisierung abspeichern zu können, müssen diese
bestimmte Voraussetzungen erfüllen.
1 Die Namensräume System.Xml und System.Xml.Serialization werden eingebunden.
Le
Damit wir die XML-Klassen verwenden können, binden wir mit dem Befehl using die erforderlichen Namensräume ein.
2 Die zu serialisierenden Objekte müssen einen Standardkonstruktor sowie öffentliche Eigenschaften haben.
Da diese Anforderungen dem Prinzip der Kapselung widersprechen, erstellen wir dafür eine
Hilfsklasse. Die Objekte werden in den Typ der Hilfsklasse übertragen.
3 Die Collection mit den zu serialisierenden Objekten muss die XML-Serialisierung
unterstützen.
Wir erzeugen dafür eine von ArrayList abgeleitete Collection, die mit Hilfe von XmlInclude
den Typ der Hilfsklasse unterstützt.
Das Fallbeispiel Fuhrpark_XML findest du
unter der ID: 1194.
Einbindung der
Namensräume für die
XML-Serialisierung
Softwareentwicklung
L 4:
Zur Serialisierung aller Fahrzeug-Objekte wird die Hilfsklasse XmlAuto mit einem Standardkonstruktor und öffentlichen Eigenschaften erstellt. Die Klasse FahrzeugList ist eine
ArrayList für die XML-Serialisierung.
// Für XML-Serialisierung erforderlich
using System.Xml;
using System.Xml.Serialization;
107
2 Objektorientiertes Programmieren
XML steht in allen Office-Anwendungen von Microsoft als Dateityp zum Speichern von Daten
zur Verfügung.
Lernen
Üben
Die Hilfsklasse benötigt
öffentliche Eigenschaften sowie einen
Konstruktor ohne
Parameter. Dieser wird
automatisch erzeugt,
wenn kein Konstruktor
implementiert wird.
Wissen
// Hilfsklasse für XML-Serialisierung
public class XmlAuto
{
public string Bezeichnung;
public double Kosten;
}
// Die Klasse FahrzeugList leitet von ArrayList ab und
// ermöglicht die XML-Serialisierung
[XmlInclude(typeof(XmlAuto))]
public class FahrzeugList : ArrayList
{
}
be
Die Collection FahrzeugList ist eine
ArrayList und unterstützt XML. Sie wird
später die Objekte vom
Typ XmlAuto enthalten.
Sichern
Um den Inhalt einer Collection serialisieren zu können, binden wir den Datentyp XmlAuto mittels XmlInclude in die Collection ein. Die neue Collection heißt FahrzeugList und erbt von
ArrayList.
Die XML-Datei wird
erstellt.
Mittels Serialize werden
alle Objekte der Collection in die XML-Datei
geschrieben.
ro
Die Collection wird
vom Typ FahrzeugList
übergeben.
// XML-Datei speichern in der Klasse Datenzugriff
public static void Fahrzeug_XML_Export(FahrzeugList fz)
{
XmlSerializer xs = new XmlSerializer(typeof(FahrzeugList));
string pfad = @".\";
string dateiname = "Transportkosten.xml";
XmlTextWriter tw = new XmlTextWriter(pfad + dateiname, null);
tw.Formatting = Formatting.Indented;
xs.Serialize(tw, fz);
tw.Flush();
tw.Close();
}
sep
Das Fallbeispiel Fuhrpark_XML findest du
unter der ID: 1194.
L 5:
In der Klasse Datenzugriff wird die statische Methode Fahrzeug_XML_Export() ergänzt,
der als Parameter eine Collection vom Typ FahrzeugList übergeben wird.
Le
Der Aufruf der statischen Methode Fahrzeug_XML_Export() erfolgt in einem Eventhandler.
Zuvor muss das Array vom Typ IFahrzeug in die Collection FahrzeugList kopiert werden, da
das Interface IFahrzeug bzw. die darin enthaltenen Objekte der Typen Bahn, PKW und LKW
die Voraussetzungen für die XML-Serialisierung nicht erfüllen, z.B. öffentliche Eigenschaften.
L 6:
Für den XML-Export wird ein Button mit einem Eventhandler erstellt, der die Methode
Fahrzeug_XML_Export() aufruft.
Das Fallbeispiel Fuhrpark_XML findest du
unter der ID: 1194.
Die Bahn-, PKW- und
LKW-Objekte werden
in Objekte vom Typ
XmlAuto kopiert und
in einer Collection vom
Typ FahrzeugList abgelegt.
108
// Eventhandler
private void btXMLExport_Click(object sender, EventArgs e)
{
FahrzeugList fzlist = new FahrzeugList();
foreach(IFahrzeug fz in fahrzeug)
{
XmlAuto auto = new XmlAuto();
auto.Bezeichnung = fz.Bezeichnung;
auto.Kosten = fz.Kosten;
fzlist.Add(auto);
}
Datenzugriff.Fahrzeug_XML_Export(fzlist);
}
Softwareentwicklung
Lerneinheit 4: Datenspeicherung
Wie kann ich mir den Inhalt
von XML-Dateien ansehen?
Wenn du auf eine XML-Datei doppelklickst, öffnet sich automatisch
der Internet Explorer bzw. ein anderer XML-fähiger Editor. Auch
in Visual Studio 2005 findest du einen XML-Editor, mit dem du die
Inhalte der XML-Dateien anzeigen kannst.
Da wir bereits eine XML-Datei abgespeichert haben, soll nun eine Methode zum Einlesen und
Darstellen der gespeicherten Daten erstellt werden.
Das Ergebnis des XMLImports wird in der
Listbox angezeigt.
Mr. What und
Ms. Check
be
ro
sep
Die Methode liefert
eine Collection mit den
eingelesenen Fahrzeugobjekten zurück.
// XML-Datei einlesen in der Klasse Datenzugriff
public static FahrzeugList Fahrzeug_XML_Import()
{
XmlSerializer xs = new XmlSerializer(typeof(FahrzeugList));
string pfad = @".\";
string dateiname = "Transportkosten.xml";
XmlTextReader tr = new XmlTextReader(pfad + dateiname);
FahrzeugList fz = (FahrzeugList) xs.Deserialize(tr);
tr.Close();
return fz;
}
// Eventhandler
private void btXMLImport_Click(object sender, EventArgs e)
{
listFuhrparkFahrtkosten.Items.Clear();
foreach (XmlAuto auto in Datenzugriff.Fahrzeug_XML_Import())
{
listFuhrparkFahrtkosten.Items.Add(
auto.Bezeichnung + ": " + auto.Kosten.ToString("C"));
}
}
Le
Das Fallbeispiel Fuhrpark_XML findest du
unter der ID: 1194.
L 7:
In der Klasse Datenzugriff wird die statische Methode Fahrzeug_XML_Import() ergänzt,
die als Rückgabewert eine Collection vom Typ FahrzeugList liefert.
Wofür werden XML-Dateien
in der Praxis verwendet?
Das XML-Format ist ein ideales Datenaustauschformat, z.B. wenn
du Objektdaten über das Internet übertragen möchtest. Zum Abspeichern und Verwalten großer Datenmengen eignen sich relationale Datenbanken besser.
Nachdem wir das Abspeichern von Text- und XML-Dateien kennengelernt haben, beschäftigen wir uns nun mit dem Zugriff auf relationale Datenbanken, wie z.B. Microsoft Access
und Microsoft SQL-Server. Diese Form der Datenspeicherung stellt für wirtschaftliche Anwendungen, z.B. eine Kundenverwaltung, ein Auftragssystem oder einen Webshop, die ideale Lösung dar.
Softwareentwicklung
109
2 Objektorientiertes Programmieren
Mr. What und
Ms. Check
Lernen
Üben
Sichern
Wissen
5 Datenbankzugriff mit ADO.NET
Verwendung relationaler Datenbanken
Das .NET-Framework liefert mit ADO.NET eine umfassende Technologie für die Arbeit mit
verschiedenen Datenquellen. Am häufigsten wird der Zugriff auf relationale Datenbanken
verwendet, wie z.B. Microsoft Access und Microsoft SQL-Server.
Im Rahmen des Faches Wirtschaftsinformatik wurden relationale Datenbanken anhand von
Microsoft Access sowie die Verwendung von SQL-Befehlen bereits behandelt. Wir konzentrieren
uns daher zunächst auf die Verwendung von Tabellen und Abfragen aus einer Access-Datenbank. Später werden wir auch auf SQL-Server-Datenbanken zugreifen.
Die folgende Abbildung gibt einen Überblick über den Aufbau der ADO.NET-Klassen.
be
ADO.NET-Datenbankzugriff
DataSet
Read
DataView
DataTable
ro
DataRelation
Write
Read-only
DataProvider
DataReader
sep
DataAdapter
Command
Connection
Diese Abbildung findest
du in der PowerPointPräsentation unter der
ID: 1194.
Abb.: Aufbau von ADO.NET
Le
Datenbankzugriff
1 Die Verbindung zu einer Access-Datenbank erfolgt über ein Connection-Objekt,
das aus der Klasse OleDbConnection instanziert wird.
Bei der Instanzierung des Connection-Objektes wird im Konstruktor ein ConnectionString angegeben, der sich aus folgenden Bestandteilen zusammensetzt:
Provider=Microsoft.Jet.OLEDB.4.0 für Microsoft Access 2003
Data Source=Datenbankname.mdb
User=Admin
Password=pw
Die Angabe von User und Passwort ist nur erforderlich, wenn die Datenbank geschützt ist.
Die Verbindung zur Datenbank wird über die Methode Open() geöffnet und über die Methode Close() geschlossen.
2 Über ein Command-Objekt wird ein SQL-Befehl ausgeführt.
Der SQL-Befehl sowie das bereits erzeugte Connection-Objekt werden im Konstruktor
des Command-Objektes angegeben. Das Command-Objekt bietet über die Methode
ExecuteReader() die Ausführung von Select und über ExecuteNonQuery() die Ausführung einer Aktionsabfrage an, z.B. Insert, Update, Delete.
110
Softwareentwicklung
Lerneinheit 4: Datenspeicherung
3 Ein DataReader-Objekt repräsentiert das Ergebnis einer Select-Abfrage. Es ermöglicht nur Lesezugriffe.
4 Eine Alternative zum DataReader stellt der DataAdapter dar. Er dient dem Befüllen eines DataSets und unterstützt Lese- und Schreibzugriffe.
Mit Hilfe der Fill()-Methode des DataAdapter-Objektes wird der Inhalt einer Select-Abfrage in ein DataSet-Objekt kopiert. Die Veränderungen im DataSet werden über die Methode Update() des DataAdapters in die Datenbank zurückgeschrieben.
Klasse
Beschreibung
OleDbConnection
Stellt eine Verbindung zur Datenbank her
OleDbCommand
Führt einen SQL-Befehl aus
OleDbDataReader
Direkter Lesezugriff auf die Datenbank
OleDbDataAdapter
Füllt ein DataSet mit dem Ergebnis eines SQL-Befehls
DataSet
Enthält eine oder mehrere Tabellen mit Beziehungen
ro
Die Klassen für den
Zugriff auf einen
SQL-Server heißen
SQLConnection,
SQLCommand,
SQLDataReader und
SQLDataAdapter.
be
Die Tabelle fasst nochmals die wichtigsten Klassen für den Datenbankzugriff zusammen:
Auswahlabfragen mit DataReader
sep
Das folgende Lehrbeispiel zeigt die Verwendung des DataReader-Providers zum Einlesen der
Fahrzeuge aus einer Access-Datenbank. Die Methoden für den Datenbankzugriff erstellen wir in
der bereits vorhandenen Klasse Datenzugriff.
L 8:
Einlesen der Tabelle T_Auto aus der Access-Datenbank Fuhrpark.mdb.
Die statische Methode
FahrzeugDB_Lesen() befüllt das Fahrzeug-Array
im Hauptprogramm.
Erzeugen des
Connection-Objektes
mit dem ConnectionString für eine AccessDatenbank
SQL-Befehl an das
Command-Objekt übergeben
Das DataReaderObjekt dr enthält
die Datensätze der
Tabelle T_Auto.
Softwareentwicklung
using System.Data.OleDb;
...
class Datenzugriff
{
...
// Access-Datenbank einlesen
public static void
FahrzeugDB_Lesen(ref IFahrzeug[] fahrzeug)
{
// Fahrzeug-Collection
ArrayList fz = new ArrayList();
fz.Add(new Bahn());
Le
Das Fallbeispiel
Fuhrpark_DB findest
du unter der ID: 1194.
// Connection-Objekt
string dbname = "Fuhrpark.mdb";
OleDbConnection conn =
new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;"
+ "Data Source=" + dbname + ";");
conn.Open();
// Command-Objekt
OleDbCommand cmd =
new OleDbCommand("SELECT * FROM T_Auto", conn);
// DataReader-Objekt
OleDbDataReader dr = cmd.ExecuteReader();
Auswahlabfrage
111
2 Objektorientiertes Programmieren
Das Ausführen der ExecuteReader()-Methode des Command-Objektes liefert als Ergebnis
das fertige DataReader-Objekt zurück. Ein Konstruktoraufruf ist nicht erforderlich. Mit Hilfe
einer while-Schleife iterieren wir durch die Datensätze.
Der PKW- bzw. LKWKonstruktor erzeugt die
Objekte.
Die Close()-Methoden
geben die reservierten
Ressourcen wieder frei.
Bereitstellen der
Objekte im FahrzeugArray.
Wissen
while (dr.Read())
{
string kennzeichen = dr["Kennzeichen"].ToString();
string marke = dr["Marke"].ToString();
double verbrauch = Convert.ToDouble(dr["Verbrauch"]);
double tankinhalt = Convert.ToDouble(dr["Tankinhalt"]);
if (dr["Fahrzeugtyp"].ToString() == "Pkw")
{
Motor motor;
if (dr["Motor"].ToString() == "B")
motor = Motor.Benzin;
else
motor = Motor.Diesel;
bool vignette = Convert.ToBoolean(dr["Vignette"]);
fz.Add( new Pkw(kennzeichen, marke, verbrauch,
tankinhalt, motor, vignette) );
}
else
{
byte achszahl = Convert.ToByte(dr["Achszahl"]);
fz.Add( new Lkw(kennzeichen, marke, verbrauch,
tankinhalt, achszahl) );
}
}
be
Mit jedem Schleifendurchlauf wird in dr
ein anderer Datensatz
repräsentiert.
Sichern
// Alles schließen
dr.Close();
conn.Close();
ro
Üben
// Arraylist in das Array fahrzeug umkopieren
fahrzeug = new IFahrzeug[fz.Count];
fz.CopyTo(fahrzeug);
}
}
sep
Lernen
Beachte
Le
Die Methode FahrzeugDB_Lesen() ersetzt die Methode Fahrzeugdatei_Lesen(). Das Ergebnis beider Methoden ist das Befüllen des Fahrzeug-Arrays mit den PKW- und LKW-Objekten.
Die Daten werden aus der Access-Tabelle T_Auto der Datenbank Fuhrpark.mdb eingelesen.
Die Datentypen der Datenbank sind mit den .NET-Datentypen nicht kompatibel und
müssen konvertiert werden.
Aktionsabfragen mit ExecuteNonQuery()
Der Zugriff über DataReader erlaubt nur die Ausführung von Select-Befehlen. Mit
ExecuteNonQuery können auch Aktionsabfragen, z.B. Insert, Update und Delete, durchgeführt werden.
Häufig werden zur Ausführung von Abfragen Parameter benötigt. Die sichere Übergabe von
Parametern erfolgt über Parameter-Objekte, die aus der Klasse OleDbParameter instanziert
werden. Durch die Verwendung von Parametern erreichen wir zwei wichtige Ziele:
Das sichere Übertragen von .NET-Datentypen in die Datentypen der Datenbank.
Das Verhindern von benutzerseitig eingefügten bösartigen SQL-Befehlen, sogenannten
SQL-Injections. Auf diesen Punkt werden wir im Rahmen von ASP.NET genauer eingehen.
Das folgende Lehrbeispiel zeigt die Verwendung einer Insert-Aktionsabfrage mit Parametern zur Übergabe der Objekt-Eigenschaften Bezeichnung und Kosten.
112
Softwareentwicklung
Lerneinheit 4: Datenspeicherung
L 8:
Anfügen der Transportkosten an die Tabelle T_Transportkosten in der Datenbank.
SQL-Befehl mit Parameternamen an das
Command-Objekt übergeben
// Transportkosten in der Datenbank speichern
public static void
TransportkostenDB_Schreiben(ref IFahrzeug[] fahrzeug)
{
// Connection-Objekt
string dbname = "Fuhrpark.mdb";
OleDbConnection conn =
new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;"
+ "Data Source=" + dbname + ";");
conn.Open();
foreach (IFahrzeug fz in fahrzeug)
{
// Command-Objekt
OleDbCommand cmd =
new OleDbCommand("INSERT INTO T_Transportkosten "
+ "([Bezeichnung], [Kosten]) "
+ "VALUES (@bez, @kost)", conn);
2 Objektorientiertes Programmieren
Erzeugen des
Connection-Objektes
mit dem ConnectionString für eine AccessDatenbank.
using System.Data.OleDb;
be
Das Fallbeispiel
Fuhrpark_DB findest
du unter der ID: 1194.
OleDbParameter kost =
cmd.Parameters.Add("@kost", OleDbType.Double);
kost.Value = fz.Kosten;
sep
Das DataReaderObjekt dr enthält
die Datensätze der
Tabelle T_Auto.
ro
// Parameter
Parameter
OleDbParameter bez =
cmd.Parameters.Add("@bez", OleDbType.VarChar, 50);
bez.Value = fz.Bezeichnung;
// SQL-Befehl ausführen
cmd.ExecuteNonQuery();
}
Aktionsabfrage
// Alles schließen
conn.Close();
}
Mr. What und
Ms. Check
Le
Die beiden Parameterobjekte bez und kost sorgen für eine sichere Übergabe der .NET-Datentypen String und Double an die Datenbank.
Was bedeutet VarChar beim
Bezeichnung-Parameter?
In einer Datenbank gibt es andere Datentypen als im .NET-Framework. Dem .NET-Datentyp String entsprechen die DatenbankDatentypen Char bzw. VarChar. Bei Char wird der übergebene Text
auf die definierte Länge mit Leerzeichen aufgefüllt, VarChar belegt
nur den tatsächlich benötigten Speicherplatz.
n-Tier-Architektur
Wie wir bereits wissen, gibt es für den Datenbankzugriff über ADO.NET zwei Techniken:
 Die Verwendung eines Command-Objektes mit der Methode ExecuteNonQuery() bzw.
das Einlesen in ein DataReader-Objekt sowie
 die Verwendung eines Command-Objektes im Zusammenspiel mit einem DataAdapter
und einem DataSet.
Die Three-Tier-Architektur wird zur n-Tier-Architektur erweitert.
Softwareentwicklung
113
Lernen
Üben
Sichern
Wissen
Sowohl das DataReader- als auch das DataSet-Objekt repräsentieren das Ergebnis der Datenabfrage, losgelöst von der Datenbank im Hauptspeicher, in Form des Data Access Tiers.
Die Business-Logik der Anwendung ist im Fahrzeug-Array gekapselt.
Das Einlesen und Abspeichern der Fahrzeug-Objekte erfolgt über den Data Access Tier, die
Interaktion mit dem Benutzer über den Presentation Tier, z.B. ein Windows-Formular.
Im Data Tier werden die Daten persistent abgelegt (Datenbank).
Presentation Tier
DataReader
DataAdapter
Command
Connection
Connection
Diese Abbildung findest
du in der PowerPointPräsentation unter der
ID: 1194.
Data Tier
sep
Datenbank
Data Access Tier
ro
Command
Business Logic Tier
be
DataSet
Abb.: n-Tier-Architektur
Das DataReader-Objekt verwendet zum Einlesen der Daten einen serverseitigen Cursor, der
nur unidirektionale Lesezugriffe erlaubt (nur vorwärts). Die Veränderung der Daten ist nicht
möglich.
Datenbankzugriff mit DataAdapter und DataSet
Le
Ein DataSet-Objekt kann eine Tabelle enthalten oder mehrere, die miteinander in Beziehung
stehen. Das DataSet ist von den Daten in der Datenbank entkoppelt. Die Verbindung zur Datenbank wird über ein DataAdapter-Objekt hergestellt.
Die folgende Tabelle fasst die wichtigsten Klassen im Zusammenhang mit DataSets zusammen:
Klasse
Beschreibung
DataSet
Container für Tabellen und Beziehungen
DataView
Sicht auf eine DataTable, z.B. zum Sortieren und Suchen
DataTable
Datentabelle, die aus Zeilen und Spalten besteht
DataRow
Zeile einer DataTable (Datensatz)
DataColumn
Spalte einer DataTable (Feld)
DataRelation
Beziehung zwischen DataTables
Constraint
Einschränkung innerhalb einer DataTable
Die Methode Fahrzeug_DataSetLesen() in der Klasse Datenzugriff im Lehrbeispiel 10 implementiert das Einlesen der Fahrzeuge aus der Access-Datenbank mit Hilfe eines DataSets.
114
Softwareentwicklung
Lerneinheit 4: Datenspeicherung
Das Fallbeispiel
Fuhrpark_DB findest
du unter der ID: 1194.
using System.Data.OleDb;
using System.Data;
...
// Access-Datenbank in DataSet einlesen
public static void Fahrzeug_DataSetLesen(ref IFahrzeug[] fahrzeug)
{
// Fahrzeug-Collection
ArrayList fz = new ArrayList();
fz.Add(new Bahn());
be
// Connection-Objekt
string dbname = "Fuhrpark.mdb";
Connection
OleDbConnection conn =
new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;"
+ "Data Source=" + dbname + ";");
conn.Open();
Das DataSet steht nach
dem Schließen der Connection weiterhin zur
Verfügung.
Der Zugriff auf das
DataSet erfolgt über
die DataTable Fahrzeug
und die darin enthaltenen DataRows.
// Connection schließen
conn.Close();
DataAdapter
DataSet
sep
Die Fill-Methode des
DataAdapters befüllt
das DataSet mit den
eingelesenen Daten.
// DataSet befüllen
OleDbDataAdapter da =
new OleDbDataAdapter(cmd);
DataSet ds = new DataSet();
da.Fill(ds, "Fahrzeug");
// DataTable aus DataSet erzeugen
DataTable dt = ds.Tables["Fahrzeug"];
foreach(DataRow dr in dt.Rows)
{
string kennzeichen = dr["Kennzeichen"].ToString();
string marke = dr["Marke"].ToString();
double verbrauch = Convert.ToDouble(dr["Verbrauch"]);
double tankinhalt = Convert.ToDouble(dr["Tankinhalt"]);
if (dr["Fahrzeugtyp"].ToString() == "Pkw")
{
Motor motor;
if (dr["Motor"].ToString() == "B")
motor = Motor.Benzin;
else
motor = Motor.Diesel;
bool vignette = Convert.ToBoolean(dr["Vignette"]);
fz.Add(new Pkw(kennzeichen, marke, verbrauch,
tankinhalt, motor, vignette));
}
else
{
byte achszahl = Convert.ToByte(dr["Achszahl"]);
fz.Add(new Lkw(kennzeichen, marke, verbrauch,
tankinhalt, achszahl));
}
}
Le
Der DataAdapter stellt
die Verbindung zum
Command-Objekt her.
ro
// Command-Objekt
Command
OleDbCommand cmd =
new OleDbCommand("SELECT * FROM T_Auto", conn);
// Arraylist in das Array fahrzeug umkopieren
fahrzeug = new IFahrzeug[fz.Count];
fz.CopyTo(fahrzeug);
}
Softwareentwicklung
115
2 Objektorientiertes Programmieren
L 10:
Verwendung eines DataSets zum Einlesen der Fahrzeuge aus der Access-Datenbank.
Lernen
Üben
Beachte
Sichern
Wissen
Die Fill-Methode des DataAdapters ermöglicht das Lesen aus der Datenbank, die Update-Methode das Aktualisieren (Zurückschreiben) der Daten.
L 11:
Der folgende Programmcode demonstriert die Aktualisierung des DataSets mit Hilfe der
Update-Methode des DataAdapters.
be
public static void DataSetDemo()
{
// Connection-Objekt
string dbname = "Fuhrpark.mdb";
OleDbConnection conn =
new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;"
+ "Data Source=" + dbname + ";");
conn.Open();
// Command-Objekt zum Einlesen
OleDbCommand cmd =
new OleDbCommand("SELECT * FROM T_AutoKopie", conn);
Die Werte in der DataTable werden einfach
überschrieben.
Die Delete-Methode
löscht den aktuellen
Datensatz aus der
DataTable.
Das CommandBuilderObjekt erstellt die erforderlichen SQL-Befehle
für die Aktualisierung,
die Update-Methode
führt sie aus.
116
// Neues Auto anfügen
DataRow new_dr = dt.NewRow();
new_dr["Kennzeichen"] = "KS-123A";
new_dr["Fahrzeugtyp"] = "Pkw";
new_dr["Marke"] = "Volvo V50";
new_dr["Verbrauch"] = 6.5;
new_dr["Tankinhalt"] = 65;
new_dr["Motor"] = "D";
new_dr["Vignette"] = false;
dt.Rows.Add(new_dr);
sep
Neuer Datensatz
// Den Verbrauch aller Dieselfahrzeuge um 10 % reduzieren
foreach (DataRow dr in dt.Rows)
{
double verbrauch = Convert.ToDouble(dr["Verbrauch"]);
if (dr["Motor"].ToString() == "D")
Datensatz aktualisieren
dr["Verbrauch"] = verbrauch / 1.1;
}
Le
Mit der Methode NewRow() wird ein neuer
Datensatz in der DataTable erstellt.
ro
// DataSet befüllen
OleDbDataAdapter da =
new OleDbDataAdapter(cmd);
DataSet ds = new DataSet();
da.Fill(ds, "Fahrzeug");
DataTable dt = ds.Tables["Fahrzeug"];
// Maserati löschen
foreach (DataRow dr in dt.Rows)
{
if (dr["Marke"].ToString() == "Maserati")
dr.Delete();
}
Datensatz löschen
// Aktualisierungsbefehle automatisch erzeugen
OleDbCommandBuilder cb = new OleDbCommandBuilder(da);
// Aktualisierung durchführen
da.Update(dt);
// Connection schließen
conn.Close();
}
Softwareentwicklung
Lerneinheit 4: Datenspeicherung
Wie kann ich die Tabelle
einer Datenbank ohne Programmierung in einem Windows-Formular darstellen?
Über die Toolbox fügst du ein DataGridView-Control in das Windows-Formular ein und konfigurierst dafür einen Datenbankzugriff. Das Control erledigt alle Aufgaben, wie z.B. Datensätze
anzeigen, sortieren, anfügen, ändern oder löschen, vollautomatisch
und ohne eine einzige Zeile Programmcode.
6 DataGridView-Control
be
Codeless-Datenbankanbindung
DataGridView-Control
in der Toolbox
Diese Abbildung findest
du in der PowerPointPräsentation unter
der ID: 1194.
sep
DataGridView-Control
ro
Das DataGridView-Control ermöglicht die Datenbankanbindung ohne das Schreiben von Programmcode.
Abb.: DataGridView-Control
Le
DataGridView einrichten
Abb.: Datenquelle auswählen
1 Das DataGridView-Control wird aus der
Toolbox in ein Formular gezogen. Über
Choose Data Source wird eine Datenquelle
ausgewählt.
Als Datenquelle wählen wir unter Add Project
Data Source die Option Database.
2 Über die Schaltfläche New Connection
wird die Verbindung zur gewünschten Datenbank hergestellt.
Der Connection-String wird automatisch erzeugt und kann im Dialog angezeigt werden.
Connection-String
Abb.: Verbindung zur Access-Datenbank herstellen
Softwareentwicklung
117
2 Objektorientiertes Programmieren
Mr. What und
Ms. Check
Lernen
Üben
Sichern
Wissen
3 Der Connection-String wird in den Project-Settings gespeichert. Der Pfad für die
Datenbank kann dort jederzeit geändert werden.
be
Über das Menü Project | Settings kann der Connection-String im Register Settings angepasst werden.
Abb.: Connection-String speichern
4 In einem DataGridView-Control können Tabellen oder Abfragen dargestellt werden. Die
Auswahl der Felder erfolgt durch Aktivieren
der Checkboxes.
sep
ro
Die Spaltenbreite der Felder kann über das Kontextmenü des Controls eingestellt werden.
Abb.: Auswahl der darzustellenden Daten
Der Datenbankpfad wird im Connection-String angegeben und kann jederzeit über die
Project-Settings verändert werden.
Le
Beachte
Abb.: Project-Settings
Durch die Festlegung der Datenbank in den
Project-Settings ist eine Änderung der Datenquelle jederzeit problemlos durchführbar, z.B.
die Verwendung eines SQL-Servers statt einer
Access-Datenbank.
118
Softwareentwicklung
2 Objektorientiertes Programmieren
Lerneinheit 4: Datenspeicherung
Abb.: DataGridView-Control mit Daten
be
Kann ich das DataGridViewControl auch für Web-Anwendungen verwenden?
Im Kapitel zu ASP.NET wirst du ein ähnliches Control für WebAnwendungen kennenlernen.
ro
Mr. What und
Ms. Check
Übungsbeispiele
sep
Üben
Ü 2:
Erstelle eine Textdatei mit folgendem Inhalt:
OS101;London;2100;80
OS456;Paris;1700;65
OS898;New York;11200;127
OS234;Los Angeles;18900;116
a) Erstelle die Klasse Flugziel mit den Eigenschaften Flugnummer, Zielort, Flugstrecke und
Passagieranzahl.
Le
b) Erstelle eine Datenzugriffsklasse, mit der du die Daten aus der Textdatei in ein Flugziel-Array
einlesen kannst.
c) Stelle die Daten aus dem Flugziel-Array in einer ListBox dar.
d) Berücksichtige den Rückflug und verdopple dafür die Flugstrecke jedes Objektes im Flugziel-Array.
e) Serialisiere alle Objektdaten in eine XML-Datei.
Ü 3:
Erstelle in einer Access-Datenbank die folgende Tabelle T_Flugziel:
Flugnummer
Zielort
Flugstrecke
Passagieranzahl
OS101
OS456
London
2100
80
Paris
1700
65
PS898
New York
11200
127
OS234
Los Angeles
18900
116
Erstelle eine Windows-Anwendung und zeige die Flugziele mit allen Daten aus der AccessTabelle in einem DataGridView-Control an.
Softwareentwicklung
119
Lernen
Üben
Sichern
Wissen
Ü 4:
Verwende die Datenbank mit der Tabelle T_Flugziel aus dem Übungsbeispiel Ü 3.
Erstelle eine Windows-Anwendung und zeige alle Langstreckenflüge (Flugstrecke > 10000)
aus der Access-Tabelle in einer ListBox an. Verwende zur Lösung der Aufgabe einen DataReader.
Ü 5:
Verwende die Datenbank mit der Tabelle T_Flugziel aus dem Übungsbeispiel Ü 3.
Erhöhe bei den Flügen mit mehr als 100 Passagieren die Passagieranzahl um zwei. Verwende für
diese Aufgabe ein DataSet. Gib die veränderten Daten in einer ListBox aus.
Zusätzlich zu diesen Übungen findest du in SbX eine Internetaufgabe.
be
ID: 1195
Sichern
ro
In dieser Lerneinheit haben wir den Zugriff auf Textdateien, die Serialisierung von Objekten in XML-Dateien sowie den Datenbankzugriff kennengelernt:
Bei der Erstellung von Anwendungen werden die Klassen der Präsentationsschicht (Presentation Tier), der Geschäftslogik (Business Logic Tier, Middle Tier) sowie der Datenschicht (Data
Tier) voneinander getrennt.
Textdateien
Der Zugriff auf Textdateien erfolgt mit den Klassen StreamReader und StreamWriter.
sep
3-SchichtenArchitektur
Das .NET-Framework bietet die Klassen Directory, DirectoryInfo und File für diverse Dateisystemoperationen an.
XML-Serialisierung
Unter XML-Serialisierung wird das Speichern bzw. Einlesen von Objekten der Geschäftslogik verstanden, wobei als Datenformat XML verwendet wird.
ADO.NET
Für einen Datenbankzugriff werden zunächst ein Connection- sowie ein Command-Objekt
instanziert. Die Daten werden entweder in einem DataReader-Objekt oder mit Hilfe eines
DataAdapters in einem DataSet repräsentiert.
n-SchichtenArchitektur
Von einer vielschichtigen Architektur spricht man, wenn die Geschäftslogik in eine weitere
Klasse für den Datenzugriff (Data Access Tier) aufgeteilt wird.
DataGridViewControl
Mit dem DataGridView-Control wird der Inhalt einer Tabelle oder Abfrage in einer Windows-Anwendung dargestellt.
Le
DateisystemOperationen
Zusätzlich zu dieser Zusammenfassung findest du in SbX eine Bildschirmpräsentation.
ID: 1196
Wissen
Wiederholungsfragen und -aufgaben
1.Beschreibe die Schichten der Drei-Schichten-Architektur!
2.Mit welchen Klassen erfolgt das Lesen- bzw. Schreiben von Text- bzw. XML-Dateien?
120
Softwareentwicklung
Lerneinheit 4: Datenspeicherung
3.Welche Klassen werden für Dateisystemoperationen verwendet?
4.Was bedeutet XML-Serialisierung?
5.Erkläre den Aufbau von ADO.NET!
7.Worin unterscheiden sich die Drei-Schichten- und die n-Schichten-Architektur?
8.Wofür eignet sich ein DataGridView-Control?
be
9.Wie kann bei der Verwendung der Methode ExecuteNonQuery() die Ausführung bösartiger SQL-Befehle, sogenannter SQL-Injections, verhindert werden?
10.Wo kann bei Verwendung eines DataGridView-Controls der Datenbankpfad geändert
werden?
11.Welche Informationen sind in einem Connection-String enthalten?
Lerncheck
Ich kann jetzt …
ro
Zusätzlich zu diesen Aufgaben findest du in SbX ein Quiz.
ID: 1197
sep
w ... Objektdaten der Geschäftslogik in der Datenschicht als Text- oder XML-Datei persistent
abspeichern.
w ... mit Hilfe von ADO.NET auf Datenbanken zugreifen und Tabellen sowie Abfragen verwenden.
w ... Dateisystemoperationen in meinen Programmen anwenden.
Le
w ... mit einem DataGridView-Control Datenobjekte präsentieren.
Softwareentwicklung
121
2 Objektorientiertes Programmieren
6.Erkläre die Unterschiede zwischen einem Datenbankzugriff über ein DataReader- bzw. ein
DataSet-Objekt!
Lernen
Üben
Sichern
Wissen
Kapitelrückblick
In diesem Kapitel haben wir die Grundlagen der objektorientierten Programmierung sowie die
Verwendung der ADO.NET-Klassen zum Speichern von Daten gelernt.
Was genau sollte ich
nun eigentlich wissen?
be
Anhand des Lernchecks hier am Kapitelende kannst du
leicht überprüfen, ob du wirklich alles verstanden hast!
Lerncheck
ro
Ich kann jetzt …
w ... Klassen und deren Bestandteile verwenden, um Objekte zu instanzieren.
w ... Konstruktoren überladen sowie statische Eigenschaften und statische Methoden richtig
einsetzen.
w ... die Bestandteile einer Klasse in Subklassen vererben und Konstruktormethoden der Basisklasse wiederverwenden.
sep
w ... virtuelle Methoden erstellen, in den Subklassen überschreiben sowie das späte Binden
einsetzen.
w ... gegen Klassen und gegen Interfaces programmieren und meine Klassen durch Mehrfachvererbung flexibler gestalten.
w ... Objektdaten der Geschäftslogik in der Datenschicht als Text- oder XML-Datei persistent
abspeichern sowie mit Hilfe von ADO.NET auf Datenbanken zugreifen.
w ... Dateisystemoperationen in meinen Programmen anwenden.
w ... mit einem DataGridView-Control Datenobjekte präsentieren.
Le
Zusätzlich findest du in SbX eine Bildschirmpräsentation zu diesem Kapitel.
ID: 1198
Im nächsten Kapitel beschäftigen wir uns mit der Planung und Modellierung von Programmen
und deren Daten mittels verschiedener UML-Diagramme.
122
Softwareentwicklung
Herunterladen