Die Präsentation wird geladen. Bitte warten

Die Präsentation wird geladen. Bitte warten

Konzepte objektorientierter Programmierung: Objekte und Klassen

Ähnliche Präsentationen


Präsentation zum Thema: "Konzepte objektorientierter Programmierung: Objekte und Klassen"—  Präsentation transkript:

1 Konzepte objektorientierter Programmierung: Objekte und Klassen
Klaus Becker 2016

2 Spiele am Computer "Objektorientierung ist die derzeitige Antwort auf die gestiegene Komplexität der Softwareentwicklung." Oestereich: Objektorientierte Software-Entwicklung Wir werden hier einfache Spielprogramme mit Hilfe von Softwarebausteinen entwickeln. Dabei sollen die Grundideen und Fachkonzepte der objektorientierten Programmierung im Vordergrund stehen und Schritt für Schritt entwickelt werden.

3 Objekte als Softwarebausteine
Teil 1 Objekte als Softwarebausteine

4 Das Spiel 17-und-4 Wir spielen 17-und-4 hier in einer vereifachten Version. Man benötigt hierzu einen Kartenstapel, bei dem die Karten gut durchmischt sind. Die Spieler können jetzt (reihum) Karten ziehen. Ziel ist es, mit den gezogenen Karten der Zahl 21 - also 17 und 4 - möglichst nahe zu kommen. Wer mit den gezogenen Karten mehr als 21 erzielt, hat verloren. Jede Karte hat dabei einen festgelegten Kartenwert: 11 10 9 8 7 4 3 2 Ziel ist es, das Spiel 17-und-4 mit Hilfe geeigneter Softwarebausteine zu simulieren. Günstig wäre es, wenn man einen Softwarebaustein hätte, der sich genauso verhält wie ein realer Kartenstapel.

5 Ein Kartenstapel mischen Karte ziehen ist leer? vorhandene Karten
gezogene Karte Ein Kartenstapel besteht aus einer Ansammlung noch vorhandener Karten (und ggf. einer gezogenen Karte). Einen Kartenstapel kann man mischen. Wenn er nicht leer ist, dann kann man die oberste Karte ziehen.

6 Ein Kartenstapel mischen Karte ziehen ist leer? vorhandene Karten
gezogene Karte Kartenstapel-Objekt Ein Softwareobjekt zur Simulation eines Kartenstapels muss also die noch vorhandenen Karten verwalten können. Zudem muss es Operationen zur Verarbeitung der verwalteten Daten vorsehen, die den Operationen eines realen Kartenstapels entsprechen: Karten mischen überprüfen, ob überhaupt noch Karten vorhanden sind Karte ziehen

7 Experimente mit Kartenstapel-Objekten
# # Kartenstapel from random import randint class Kartenstapel(object): Bauplan für Kartenstapel-Objekte Kartenstapel-Objekt Wir stellen hier einen Bauplan zur Erzeugung von Kartenstapel-Softwareobjekten zur Verfügung. Du musst die Details des Bauplans nicht verstehen, um die nach dem Bauplan erzeugten Softwareobjekte nutzen zu können. Wir werden uns in einem der folgenden Abschnitte genauer mit solchen Bauplänen beschäftigen. Den Bauplan zur Erzeugung von Kartenstapel-Softwareobjekten findest du in der Datei kartenstapel.py. Lade diese Datei herunter und öffne sie mit dem Python-Editor. Führe den Quelltext mit [Run][Run Module] einmal aus. Beachte, dass beim Ausführen die im Quelltext vorliegende Klassendeklaration vom Python-Ausführsystem übernommen wird. Es wird jedoch kein Ergebnis im Ausführfenster angezeigt. Jetzt kann die Simulation des Kartenstapels beginnen.

8 Experimente mit Kartenstapel-Objekten
>>> kartenstapel = Kartenstapel() >>> kartenstapel <__main__.kartenstapel object at …> >>> kartenstapel.kartenListe ['X-A', 'X-K', 'X-D', 'X-B', 'X-10', 'X-9', 'X-8', 'X-7', 'P-A', 'P-K', 'P-D', 'P-B', 'P-10', 'P-9', 'P-8', 'P-7', 'H-A', 'H-K', 'H-D', 'H-B', 'H-10', 'H-9', 'H-8', 'H-7', 'K-A', 'K-K', 'K-D', 'K-B', 'K-10', 'K-9', 'K-8', 'K-7'] >>> kartenstapel.mischen() ['X-9', 'P-10', 'P-D', 'X-D', 'X-8', 'X-A', 'H-10', 'P-7', 'K-10', 'X-7', 'H-D', 'P-9', 'K-7', 'K-9', 'X-K', 'X-10', 'K-A', 'P-B', 'P-K', 'H-A', 'K-K', 'P-8', 'K-B', 'P-A', 'H-7', 'H-9', 'K-8', 'X-B', 'H-K', 'K-D', 'H-B', 'H-8'] >>> kartenstapel.istLeer() False >>> kartenstapel.karteZiehen() 'X-9' ['P-10', 'P-D', 'X-D', 'X-8', 'X-A', 'H-10', 'P-7', 'K-10', 'X-7', 'H-D', 'P-9', 'K-7', 'K-9', 'X-K', 'X-10', 'K-A', 'P-B', 'P-K', 'H-A', 'K-K', 'P-8', 'K-B', 'P-A', 'H-7', 'H-9', 'K-8', 'X-B', 'H-K', 'K-D', 'H-B', 'H-8'] Aufgaben: Analysiere den Python-Dialog und beantworte die folgenden Fragen: - Wie wird das Kartenstapel-Objekt erzeugt? - Wie inspiziert man die vom Kartenstapel-Objekt verwalteten Daten? - In welcher Reihenfolge liegen die Karten zu Beginn auf dem Kartenstapel? - Was bewirkt die Anweisung kartenstapel.mischen()? - Wie wird im Python-Dialog eine Karte "gezogen"? Welche Karte ist es hier? Führe selbst einen solchen Python-Dialog aus. Erzeuge zunächst ein Objekt kartenstapel. Führe mit diesem Objekt ein 17-und-4-Spiel (mit einem einzigen Spieler) durch. Achte genau auf die Darstellung der Details.

9 Experimente mit Kartenstapel-Objekten
from kartenstapel import Kartenstapel # Testprogramm kartenstapel = Kartenstapel() print(kartenstapel.kartenListe) print() kartenstapel.mischen() print(kartenstapel.istLeer()) gezogeneKarte = kartenstapel.karteZiehen() print(gezogeneKarte) Aufgabe: Die Verwendung eines Kartenstapel-Objekts kann man auch mit einem Testprogramm erkunden. Speichere das Testprogramm im selben Ordner ab, in dem auch die Datei kartenstapel.py mit der Klassendeklaration der Klasse Kartenstapel gespeichert ist. Führe das Testprogramm anschließend aus und erläutere die erzeugten Ausgaben.

10 Experimente mit Kartenstapel-Objekten
Aufgabe: Entwickle analog ein Testprogramm, das einen Kartenstapel erzeugt, die Karten mischt und anschließend solange die oberste Karte zieht und ausgibt, bis der Kartenstapel leer ist. Benutze dabei die Operationen, die für Kartenstapel-Objekte vorgesehen sind (siehe Objektdiagramm).

11 Objekte unserer Welt Objekte unserer Welt sind fassbare Gegenstände (wie z.B. Schuhe oder Kartenstapel) oder auch Konstrukte unseres Denkens und Handelns (wie z.B. Schuhladen oder Kartenspiel). Betrachten wir das Beispiel "Schuhe". Wenn man seine neuen Schuhe charakterisieren will, dann fallen einem sofort eine Reihe von Eigenschaften ein: Modell: Sneaker; Größe: 40; Farbe: rot; Verschluss: Schnürsenkel usw.. Schuhe haben nicht nur bestimmte Eigenschaften, mit ihnen kann man auch bestimmte "Operationen" ausführen: Zum An- und Ausziehen kann man sie in einem gewissen Sinn öffnen und schließen (z.B. durch Öffnen und Binden der Schnürsenkeln). Vielleicht kann man sie auch benutzen, um einen Nagel einzuschlagen, obwohl sie dafür eigentlich nicht gedacht sind. Objekte prägen sehr stark unser Denken. Wir können die Welt, in der wir leben, mit Hilfe von Objekten beschreiben, die Eigenschaften haben und die mit bestimmten Operationen bearbeitet werden können.

12 Software-Objekte Analog zu einer Kartenstapel (als Objekt der realen Welt) soll ein Softwareobjekt kartenstapel konzipiert werden. Das folgende Ablaufprotokoll verdeutlicht die Arbeitsweise eines Softwareobjekts kartenstapel: Das Softwareobjekt verwaltet Daten zu einem Kartenstapel (im vorliegenden Fall die Ansammlung von Karten. Das Softwareobjekt nutzt hierzu die interne Variable kartenListe, zur Verwaltung einer Liste von Zeichenketten. Das Softwareobjekt kartenstapel stellt auch eine Operation zur Verarbeitung der verwalteten Daten bereit. Im vorliegenden Fall sind das die Operationen mischen(), istLeer() und karteZiehen(). Das Softwareobjekt ist also eine Einheit, die Daten verwaltet und Operationen zur Verarbeitung der verwalteten Daten zur Verfügung stellt. Statt von Softwareobjekten wird im Folgenden kurz von Objekten gesprochen.

13 Fachkonzept - Objekt Ein Objekt ist eine autonome Software-Einheit, die für bestimmte Aufgaben zuständig ist. Ein Objekt kann Daten mit Hilfe von Attributen verwalten und Operationen zur Verarbeitung der verwalteten Daten mit Hilfe von Methoden ausführen. Attribute sind - an Objekte gebundene - Variablen zur Verwaltung von Daten. Diese entsprechen in der Regel den Eigenschaften der betreffenden Objekte. Methoden sind - an Objekte gebundene - Prozeduren oder Funktionen zur Verarbeitung von Daten. Diese Methoden werden ausgeführt, wenn das betreffende Objekt Operationen ausführt. Ein Objekt befindet sich stets in einem bestimmten Zustand. Der aktuelle Objektzustand wird durch die aktuellen Werte der Attribute festgelegt. Objekt Attribute - Attributwerte Ausführung einer Methode Objektdiagramm

14 Fachkonzept - Objekt Zugriff auf Attribute: Objekt objekt.attribut
kartenstapel.kartenListe Aktivierung von Methoden: Attribute - Attributwerte objekt.methode kartenstapel.mischen() Ausführung einer Methode Objektdiagramm

15 Übungen Aufgabe 1: Ziel ist es, Würfel mit Softwareobjekten zu simulieren. Einen Bauplan zur Erzeugung von entsprechenden Softwareobjekten findest du in der Datei wuerfel.py. Öffne diese Datei im Python-Editor und führe den Quelltext mit [Run][Run Module] einmal aus. Beachte, dass beim Ausführen die im Quelltext vorliegende Klassendeklaration vom Python-Ausführsystem übernommen wird. Es wird jedoch kein Ergebnis im Ausführfenster angezeigt. Ergänze das Objektdiagramm so, dass es die Objektkonstallation am Ende des Python-Dialogs korrekt beschreibt. >>> w1 = Wuerfel() >>> w1.augen 2 >>> w2 = Wuerfel() >>> w2.augen 1 >>> w3 = Wuerfel() >>> w3.augen 4 >>> w1.werfen() 5 >>> w3.werfen()

16 Übungen Aufgabe 2: Mit einem Programm soll die folgende Objektkonstellation erzeugt werden. Ergänze das Programmfragment und teste es. from wuerfel import Wuerfel # Testprogramm w1 = Wuerfel() w2 = Wuerfel() ... while w1.augen != 6: print(w1.augen)

17 Klassen als Baupläne für Objekte
Teil 2 Klassen als Baupläne für Objekte

18 Ein Bauplan für Kartenstapel-Objekte
from random import randint class Kartenstapel(object): def __init__(self): self.kartenListe = ['X-A', 'X-K', 'X-D', 'X-B', 'X-10', 'X-9', 'X-8', 'X-7', 'P-A', 'P-K', 'P-D', 'P-B', 'P-10', 'P-9', 'P-8', 'P-7', 'H-A', 'H-K', 'H-D', 'H-B', 'H-10', 'H-9', 'H-8', 'H-7', 'K-A', 'K-K', 'K-D', 'K-B', 'K-10', 'K-9', 'K-8', 'K-7'] def mischen(self): neueListe = [] aktuelleAnzahl = len(self.kartenListe) while aktuelleAnzahl > 0: i = randint(0, aktuelleAnzahl-1) neueListe = neueListe + [self.kartenListe[i]] del self.kartenListe[i] self.kartenListe = neueListe def istLeer(self): if len(self.kartenListe) > 0: ergebnis = False else: ergebnis = True return ergebnis def karteZiehen(self): gezogeneKarte = self.kartenListe[0] self.kartenListe = self.kartenListe[1:] gezogeneKarte = None return gezogeneKarte mischen Karte ziehen ist leer? vorhandene Karten gezogene Karte

19 Ein Kartenhaufen Was macht einen Kartenhaufen aus? Karte hinzufügen
Kartenliste Wert Unter einem Kartenhaufen soll hier eine Ansammlung von Karten verstanden werden. Einem solchen Kartenhaufen kann man weitere Karten hinzufügen. Ein Kartenhaufen hat zudem einen Gesamtwert (das ist die Summe der Werte aller Karten des Kartenhaufens). Im vorliegenden Beispiel beträgt der Gesamtwert 23.

20 Simulation eines Kartenhaufens
>>> >>> meinKartenhaufen = Kartenhaufen() >>> meinKartenhaufen.hinzufuegen('H-D') >>> meinKartenhaufen.hinzufuegen('X-A') >>> meinKartenhaufen.hinzufuegen('K-9') >>> meinKartenhaufen.kartenListe ['H-D', 'X-A', 'K-9'] >>> meinKartenhaufen.wert 23 So soll es funktionieren! Karte hinzufügen Kartenliste Wert

21 Ein Bauplan für Kartenhaufen-Objekte
class Kartenhaufen(object): def __init__(self): self.kartenListe = # ... self.wert = # ... def hinzufuegen(self, karte): if karte[2] == 'A': kartenwert = 11 elif karte[2] == 'K': kartenwert = 4 elif karte[2] == 'D': kartenwert = 3 elif karte[2] == 'B': kartenwert = 2 elif karte[2] == '1': kartenwert = 10 # ... Aufgabe: Die Klassendeklaration ist noch nicht ganz fertig. Kannst du die fehlenden Teile (mit #... markiert) ergänzen? Wenn du die Klassendeklaration richtig ergänzt hast, dann kannst du als Test einen geeigneten Python-Dialog führen. Vorher musst du die Klassendeklaration aber einmal ausführen, damit sie vom Python-Ausführsystem übernommen wird. >>> >>> meinKartenhaufen = Kartenhaufen() ...

22 Aufgabe Aufgabe: Speichere die Klassendeklarationen der Klassen Kartenstapel und Kartenhaufen in einer gemeinsamen Datei ab und führe sie einmal aus. Simuliere anschließend ein 17-und-4-Spiel mit zwei Spielern. Hier der Beginn einer solchen Simulation. >>> >>> kartenstapel = Kartenstapel() >>> kartenstapel.mischen() >>> kartenhaufenSpieler1 = Kartenhaufen() >>> kartenhaufenSpieler2 = Kartenhaufen() >>> karte = kartenstapel.karteZiehen() >>> kartenhaufenSpieler1.hinzufuegen(karte) >>> kartenhaufenSpieler2.hinzufuegen(karte) >>> kartenhaufenSpieler1.wert 10 >>> kartenhaufenSpieler2.wert 3 >>> ...

23 Aufgabe Aufgabe: In der Datei kartenspiel.py befinden sich die Deklarationen der Klassen Kartenstapel und Kartenhaufen. Analysiere das Testprogramm. Stelle eine Vermutung auf, was es leistet. Überprüfe anschließend deine Vermutung. Das Test-programm muss sich im selben Verzeichnis wie die Datei kartenspiel.py befinden. from kartenspiel import Kartenstapel, Kartenhaufen # Testprogramm kartenstapel = Kartenstapel() kartenstapel.mischen() kartenhaufenSpieler1 = Kartenhaufen() kartenhaufenSpieler2 = Kartenhaufen() print('Spieler 1:') karte = kartenstapel.karteZiehen() print(karte) kartenhaufenSpieler1.hinzufuegen(karte) print(kartenhaufenSpieler1.wert) print() print('Spieler 2:') kartenhaufenSpieler2.hinzufuegen(karte) print(kartenhaufenSpieler2.wert)

24 Aufgabe Aufgabe: In der Datei kartenspiel.py befinden sich die Deklarationen der Klassen Kartenstapel und Kartenhaufen. (a) Ein Spieler zieht seine Karten nach der folgenden Strategie: Solange der Gesamtwert aller Karten noch kleiner als 18 ist, wird eine Karte gezogen. Entwickle ein Simulationsprogramm zu dieser Strategie. (b) Ein Spieler zieht seine Karten immer nach der folgenden Strategie: Solange der Kartenwert noch kleiner als 18 ist, wird eine Karte gezogen. Ermittle mit einer Simulation, wie oft der Spieler bei dieser Strategie im Mittel über der 21 landet. Zusatz: Das Ziehen von zwei Assen soll dabei nicht mitgezählt werden.

25 Klasse als Bauplan Der Begriff "Klasse" wird hier im Sinne von Klassifizieren benutzt. Du weißt sicher, was das heißt: Wenn man klassifiziert, dann versucht man, Gemeinsamkeiten von Objekten herauszustellen. Die Klasse "Schuh" beschreibt Objekte, die man als Fußbekleidung nutzt und somit an- und ausziehen sowie tragen kann und die bestimmte Eigenschaften (wie Modell, Größe, Farbe und Verschluss) aufweisen. Wer Schuhe herstellen will, muss sich (mehr oder weniger) an der Klassenbeschreibung für Schuhe orientieren, damit das, was hergestellt wird, auch wirklich Schuhe sind. Es macht sicher keinen Sinn, sich an der Klassenbeschreibung für Hosen oder Pullover zu orientieren. Eine Klassenbeschreibung für Schuhe kann somit als eine Art Bauplan für Schuhe aufgefasst werden.

26 Fachkonzept - Klasse Eine Klasse ist ein Bauplan für Objekte. Dieser Bauplan legt genau fest, welche Attribute die zu konstruierenden Objekte haben sollen und welche Methoden sie ausführen können sollen. Klassendiagramm Ein Objekt (als Exemplar einer Klasse) ist eine Einheit, die nach dem Bauplan der zugeordneten Klasse erzeugt wurde. Ein Objekt verfügt somit über die Attribute, die in der Klasse festgelegt sind. Diesen Attributen können - im Unterschied zur Klasse - Attributwerte zugewiesen werden. Ein Objekt kann zudem sämtliche Methoden der Klasse ausführen. Ausgenommen bleibt hier nur die Methode, deren Name mit dem Klassennamen übereinstimmt (s. u.). Objekte können mit Namen versehen werden, über die sie dann gezielt angesprochen werden können. Objektdiagramm

27 Konstruktor / Destruktor
Zur Erzeugung von Objekten verfügt eine Klasse über eine spezielle Methode, die sogenannte Konstruktormethode. Zur Vernichtung von Objekten verfügt eine Klasse über eine sogenannte Destruktormethode. Konstruktor Ein Software-Objekt hat - wie Objekte der realen Welt - eine bestimmte Lebensdauer. Es muss erzeugt werden, bevor es in Aktion treten kann, und kann auch wieder vernichtet werden. In einem Klassendiagramm wird eine Konstruktormethode dadurch gekennzeichnet, dass sie denselben Namen wie die Klasse selbst trägt. Oft wird diese spezielle Methode in Klassendiagrammen aber auch weggelassen. Beachte, dass eine Konstruktormethoden keine Methode ist, die ein Objekt ausführen kann. Destruktormethoden werden in der Regel in Klassendiagrammen weggelassen.

28 Klassendeklaration in Python
Klassenname Oberklasse Schlüsselwort Doppelpunkt class Kartenhaufen(object): def __init__(self): self.kartenListe = [] self.wert = 0 def hinzufuegen(self, karte): self.kartenListe = self.kartenListe + [karte] if karte[2] == 'A': kartenwert = 11 elif karte[2] == 'K': kartenwert = 4 elif karte[2] == 'D': kartenwert = 3 elif karte[2] == 'B': kartenwert = 2 elif karte[2] == '1': kartenwert = 10 ... self.wert = self.wert + kartenwert Einrückung Konstruktor Attribute Attribute Methode Referenz auf Objekt

29 Objekterzeugung in Python
>>> meinKartenhaufen = Kartenhaufen() >>> meinKartenhaufen <__main__.Kartenhaufen object at 0x0136C4B0> >>> meinKartenhaufen.__dict__ {'wert': 0, 'kartenListe': []} Erzeugung eines Objekts Inspektion eines Objekts >>> meinKartenhaufen = Kartenhaufen() >>> meinKartenhaufen <__main__.Kartenhaufen object at 0x013ADFB0> >>> del meinKartenhaufen Traceback (most recent call last): File ... ampel1 NameError: name 'meinKartenhaufen' is not defined >>> Vernichtung eines Objekts

30 Objekterzeugung in Python
Experimente mit dem Python-Tutor

31 Übungen class Kartenhand(object): def __init__(self):
self.kartenListe = [] self.anzahl = 0 def hinzufuegen(self, karte): self.kartenListe = self.kartenListe + [karte] self.anzahl = self.anzahl + 1 def wegnehmen(self, karte): if karte in self.kartenListe: i = self.kartenListe.index(karte) del self.kartenListe[i] self.anzahl = self.anzahl - 1 >>> >>> meineKarten = Kartenhand() >>> meineKarten.hinzufuegen('P-B') >>> meineKarten.kartenListe ? >>> meineKarten.hinzufuegen('H-10') >>> meineKarten.hinzufuegen('P-A') >>> meineKarten.wegnehmen('H-10') >>> meineKarten.wegnehmen('X-7') >>> meineKarten.anzahl Aufgabe 1: (a) Analysiere zunächst die Klasse Kartenhand. Welche Attribute werden hier festgelegt? Was sollen sie verwalten? Welche Methoden gibt es? Was sollen sie leisten? Beschreibe die Klasse auch mit einem Klassendiagramm. (b) Was steht an Stelle der Fragezeichen? Überprüfe deine Vermutungen.

32 Übungen class Kartenhand(object): def __init__(self, kartenGegeben):
self.kartenListe = kartenGegeben self.anzahl = len(self.kartenListe) def hinzufuegen(self, karte): self.kartenListe = self.kartenListe + [karte] self.anzahl = self.anzahl + 1 def wegnehmen(self, karte): if karte in self.kartenListe: i = self.kartenListe.index(karte) del self.kartenListe[i] self.anzahl = self.anzahl - 1 >>> >>> meineKarten = Kartenhand(['X-A', 'H-A', 'P-7']) >>> meineKarten.kartenListe ['X-A', 'H-A', 'P-7'] >>> meineKarten.anzahl 3 Aufgabe 1: (c) Die Deklaration der Klasse Kartenhand unterscheidet sich von der oben gezeigten nur im Kontruktor. Was ist hier anders? Wozu könnte das gut sein? Betrachte hierzu auch den Python-Dialog.

33 Übungen class Kartenhand(object): def __init__(self, kartenGegeben):
self.kartenListe = kartenGegeben self.anzahl = len(self.kartenListe) def existiertKarte(self, karte): if karte in self.kartenListe: ergebnis = True else: ergebnis = False return ergebnis def hinzufuegen(self, karte): if not self.existiertKarte(karte): self.kartenListe = self.kartenListe + [karte] self.anzahl = self.anzahl + 1 def wegnehmen(self, karte): if self.existiertKarte(karte): i = self.kartenListe.index(karte) del self.kartenListe[i] self.anzahl = self.anzahl - 1 Aufgabe 1: (d) Erläutere die Unterschiede zu den bisher betrachteten Klassendeklarationen. Führe selbst einen Python-Dialog zum Testen aus. Dokumentiere mit diesem Dialog das Verhalten der einzelnen Methoden der Klasse.

34 Übungen Aufgabe 2: Gegeben ist ein Klassendiagramm zur Beschreibung einer Klasse Wuerfel. (a) Erläutere die Bestandteile der Klasse Wuerfel: Welche Daten werden hier verwaltet? Welche Operationen soll ein Wuerfel-Objekt ausführen können? (b) Implementiere zunächst die Klasse Wuerfel. Entwickle dann einen Python-Dialog zum Testen dieser Klasse. In diesem Dialog sollen zwei Würfelobjekte erzeugt und geworfen werden. (c) Ermittle mit einem Testprogramm, wie oft man einen Würfel (durchschnittlich) werfen muss, bis die Summe der Augenzahlen der Würfelwürfe die Zahl 21 überschreitet. Benutze die Klasse Wuerfel, um ein Würfelobjekt zu erzeugen.

35 Übungen Aufgabe 3: Das Spiel 17 und 4 soll hier mit einem Dodekaederwürfel gespielt werden. Ein solcher Würfel ist ein Körper mit 12 regelmäßigen Fünfecken als Flächen. Gegeben ist ein Klassendiagramm mit einem Bauplan für Dodekaederwürfel: (a) Erläutere die Bestandteile der Klasse Dodekaederwuerfel: Welche Attribute und Methoden sind vorgesehen? Wofür sind sie im vorliegenden Kontext gedacht? (b) Implementiere zunächst die Klasse Dodekaederwuerfel. Entwickle dann einen Python-Dialog zum Testen dieser Klasse. (c) Ermittle mit einem Testprogramm, wie oft man einen Dodekaederwürfel (durchschnittlich) werfen muss, bis die Summe der Augenzahlen der Würfelwürfe die Zahl 21 überschreitet. Benutze die Klasse Dodekaederwuerfel, um ein Würfelobjekt zu erzeugen.

36 Übungen Aufgabe 4: Für viele Spiele benötigt man eine Art Punktekonto. Auf dieses Konto kann man eine vorgegebene Anzahl von Punkten "einzahlen", der Punktekontostand erhöht sich dann entsprechen. Man kann analog auch eine vorgegebene Anzahl von Punkten "abheben", natürlich nur, wenn genügend Punkte auf den Konto sind. Entwickle zunächst ein Klassendiagramm mit allen benötigten Attributen und Methoden. Entwickle anschließend eine passende Implementierung und teste sie.

37 Datenkapselung bei Objekten
Teil 3 Datenkapselung bei Objekten

38 Experimente mit Kartenhaufen-Objekten
class Kartenhaufen(object): def __init__(self): self.kartenListe = [] self.wert = 0 def hinzufuegen(self, karte): self.kartenListe = self.kartenListe + [karte] if karte[2] == 'A': kartenwert = 11 elif karte[2] == 'K': kartenwert = 4 elif karte[2] == 'D': kartenwert = 3 elif karte[2] == 'B': kartenwert = 2 elif karte[2] == '1': kartenwert = 10 elif karte[2] == '9': kartenwert = 9 elif karte[2] == '8': kartenwert = 8 self.wert = self.wert + kartenwert

39 Experimente mit Kartenhaufen-Objekten
>>> >>> meinKartenhaufen = Kartenhaufen() >>> meinKartenhaufen.kartenListe = ['H-K'] >>> meinKartenhaufen.hinzufuegen('K-B') >>> meinKartenhaufen.hinzufuegen('X-9') >>> meinKartenhaufen.kartenListe ['H-K', 'K-B', 'X-9'] >>> meinKartenhaufen.wert 11 Aufgabe: (a) Welcher reale Vorgang wird hier simuliert? (b) Stimmt der angegebene Gesamtwert der Karten? Warum ist hier etwas schiefgelaufen?

40 Experimente mit Kartenhaufen-Objekten
>>> >>> meinKartenhaufen = Kartenhaufen() >>> meinKartenhaufen.setKartenListe( ['H-K']) >>> meinKartenhaufen.hinzufuegen('K-B') >>> meinKartenhaufen.hinzufuegen('X-9') >>> meinKartenhaufen.getKartenListe() ['H-K', 'K-B', 'X-9'] >>> meinKartenhaufen.getWert() 15 Kein direkter Zugriff auf die Attribute vorgesehen Aufgabe: Auf welche Weise wird hier der Zugriff auf die Attributwerte realisiert?

41 Experimente mit Kartenhaufen-Objekten
class Kartenhaufen(object): def __init__(self): self.kartenListe = [] self.wert = 0 def kartenwert(self, karte): def hinzufuegen(self, karte): def getKartenListe(self): return self.kartenListe def getWert(self): return self.wert def setKartenListe(self, vorgegebeneKarten): self.kartenListe = vorgegebeneKarten gesamtwert = 0 for karte in self.kartenListe: gesamtwert = gesamtwert + self.kartenwert(karte) self.wert = gesamtwert Strategie: Kein Zugriff auf Attribute Klasse mit Zugriffsmethoden Strategie: Zugriff auf Attribute nur mit Zugriffsmethoden

42 Experimente mit Kartenhaufen-Objekten
>>> >>> meinKartenhaufen = Kartenhaufen() >>> meinKartenhaufen.setKartenListe(['K-B', 'H-D']) >>> meinKartenhaufen.getKartenListe() ? >>> meinKartenhaufen.getWert() >>> meinKartenhaufen.hinzufuegen('X-7') >>> meinKartenhaufen.hinzufuegen('H-K') Zugriff nur mit Zugriffsmethoden Aufgabe: Welche Ergebnisse werden wohl an Stelle der Fragezeichen ausgegeben? Überprüfe deine Vermutung. Worin liegen die Vorteile, wenn nur die von einem Objekt bereitgestellten Methoden benutzt werden?

43 Das Geheimnisprinzip Wenn man die Motorhaube eines neueren Autos öffnet, dann sieht man recht wenig vom Motor. Einblick in das eigentliche Geschehen im Motor hat man nicht, wesentliche Teile des Motors werden sogar durch Abdeckungen schwer zugänglich gemacht. Man kann allenfalls überprüfen, ob man genug Öl oder Bremsflüssigkeit hat. Diese Vorgehensweise, den Motor eines Autos nur noch für Spezialisten zugänglich zu machen, wird ganz bewusst von den Autobauern gewählt. Ein Motor ist heutzutage so kompliziert, dass Laien keine Veränderungen daran vornehmen sollen. Beim Autobau wird somit - zumindest in bestimmten Bereichen - das Geheimnisprinzip angewandt. Bestimmte Eigenschaften des Motors können nur über speziell hierfür vorgesehene Schnittstellen ermittelt werden. So kann der aktuelle Ölstand nur an einem hierfür vorgesehenen Messstab abgelesen werden. Änderungen am aktuellen Motorzustand können direkt ebenfalls nur an bestimmten hierfür vorgesehenen Stellen vorgenommen werden. Motoröl lässt sich nur in die hierfür vorgesehene Öffnung einfüllen. Alles weitere über das Innere des Motors bleibt für den normalen Autofahrer unzugänglich und in diesem Sinne geheim.

44 Fachkonzept - Datenkapselung
Software-Objekte (als Programmeinheiten) werden so konzipiert, dass Details über den inneren Aufbau verborgen werden und Änderungen von Objektzuständen nur über dafür vorgesehene Methoden erfolgen können. Das Verbergen des inneren Aufbaus wird realisiert, indem man keinen direkten Zugriff auf die Attribute zur Verwaltung der internen Daten eines Objekts ermöglicht. Man nennt diese Vorgehensweise auch Datenkapselung.

45 Zugriffsrechte / Zugriffsmethoden
Um interne Daten kapseln zu können, werden Zugriffrechte festgelegt. Der Entwickler einer Klasse hat die Möglichkeit, Attribute und Methoden einer Klasse als öffentlich oder privat zu deklarieren. Lesende und schreibende Zugriffe auf Attribute bzw. Methoden eines Objekts sind nur möglich, wenn diese öffentlich sind. Private Attribute bzw. Methoden können dagegen nur bei der Implementierung der betreffenden Klasse benutzt werden. Im Klassendiagramm werden die Zugriffsrechte auf die Attribute und Methoden mit Hilfe der Symbole + (für öffentlich) und - (für privat) festgelegt. Verfolgt man die Strategie, alle Attribute als privat zu deklarieren, so besteht keine Möglichkeit, direkt schreibend oder lesend auf Attributwerte zuzugreifen. Um dennoch solche Zugriffe zu erlauben, werden spezielle öffentliche Zugriffsmethoden bereitgestellt. Das Klassendiagramm wird daher um solche Zugriffsmethoden erweitert.

46 Zugriffsrechte in Python
class Kartenhaufen(object): def __init__(self): self.__kartenListe = [] self.__wert = 0 def __kartenwert(self, karte): … def hinzufuegen(self, karte): self.__kartenListe = self.__kartenListe + [karte] self.__wert = self.__wert + self.__kartenwert(karte) def getKartenListe(self): return self.__kartenListe def getWert(self): return self.__wert def setKartenListe(self, vorgegebeneKarten): self.__kartenListe = vorgegebeneKarten gesamtwert = 0 for karte in self.__kartenListe: gesamtwert = gesamtwert + self.__kartenwert(karte) self.__wert = gesamtwert Ein Attribut wird in Python zu einem privaten Attribut, wenn der Name mit zwei Unterstrichen beginnt und nicht mit Unterstrichen endet. Beginnt der Attributname / Methodenname nicht mit einem Unterstrich, so ist das Attribut öffentlich. Entsprechendes gilt für Methoden.

47 Datenkapselung in Python
>>> meinKartenhaufen = Kartenhaufen() >>> meinKartenhaufen.setKartenListe(['K-A', 'H-A']) >>> meinKartenhaufen.__wert Traceback (most recent call last): File ... meinKartenhaufen.__wert AttributeError: 'Kartenhaufen' object has no attribute '__wert' >>> meinKartenhaufen.__dict__ {'_Kartenhaufen__wert': 22, '_Kartenhaufen__kartenListe': ['K-A', 'H-A']} >>> meinKartenhaufen._Kartenhaufen__wert 22 Wie erwartet kann man auf das private Attribut __wert des Objekts meinKartenhaufen nicht zugreifen. Python meldet als Fehler, dass es kein Attribut __wert gibt. Der Aufruf meinKartenhaufen.__dict__ verrät, woran das liegt. Ein Aufruf wie meinKartenhaufen.__dict__ listet sämtliche Attribute mit den zugehörigen Attributwerten des betreffenden Objekts auf. Interessant ist hier, dass sich das private Attribut __wert hinter einem anderen Namen versteckt. Wenn man weiß, wie der neue Name - hier _Kartenhaufen__wert - gebildet wird, dann kann man auf das betreffende Attribut zugreifen. Also: Private Attribute werden in Python mit anderen Namen versehen, so dass kein direkter Zugriff möglich ist. Kennt man den Namen, hinter dem sich ein privates Attribut verbirgt, so kann man durchaus auf dieses Attribut zugreifen. Python liefert also keinen echten Zugriffsschutz.

48 Datenkapselung in Python
>>> >>> meinKartenhaufen = Kartenhaufen() >>> meinKartenhaufen.__kartenListe Traceback (most recent call last): File … meinKartenhaufen.__kartenListe AttributeError: 'Kartenhaufen' object has no attribute '__kartenListe' >>> meinKartenhaufen.__dict__ {'_Kartenhaufen__wert': 0, '_Kartenhaufen__kartenListe': []} >>> meinKartenhaufen.__kartenListe = ['X-B'] ['X-B'] {'__kartenListe': ['X-B'], '_Kartenhaufen__wert': 0, '_Kartenhaufen__kartenListe': []} Ein erster Zugriff auf das private Attribut __kartenListe scheitert. Dann aber ist es entgegen aller Zugriffslogik scheinbar möglich, dem privaten Attribut __kartenListe einen Wert zuzuweisen. Der Aufruf meinKartenhaufen.__dict__ erklärt erst, was hier passiert ist. Neben dem privaten Attribut __kartenListe, das sich hinter dem neuen Namen _Kartenhaufen__kartenListe versteckt, gibt es noch ein öffentliches Attribut __kartenListe, auf das man direkt zugreifen kann.

49 Datenkapselung in Python
class Kartenhaufen(object): __slots__ = ('__kartenListe', '__wert') def __init__(self): self.__kartenListe = [] self.__wert = 0 # ... wie bisher ... Mit dem Attribut __slots__ wird festgelegt, welche Attribute ein Objekt der betreffenden Klasse haben darf. >>> >>> meinKartenhaufen = Kartenhaufen() >>> meinKartenhaufen.__kartenListe Traceback (most recent call last): File ... meinKartenhaufen.__kartenListe AttributeError: 'Kartenhaufen' object has no attribute '__kartenListe' >>> meinKartenhaufen.__kartenListe = ['X-B'] meinKartenhaufen.__kartenListe = ['X-B']

50 Vereinbarung zur Datenkapselung
Wir werden im Folgenden bei der Implementierung von Klassen in Python keine Attribute und Methoden als privat deklarieren. Alle Attribute und Methoden sind daher direkt zugänglich. Allerdings werden wir von dem direkten Zugriff in der Regel keinen Gebrauch machen. Nur in begründeten Sonderfällen (wie z.B. zum schnellen Testen) werden wir von dieser Vereinbarung abweichen. class Kartenhaufen(object): __slots__ = ('kartenListe', 'wert') def __init__(self): self.kartenListe = [] self.wert = 0 # ...

51 Übungen class Kartenhand(object): def __init__(self):
self.kartenListe = [] self.anzahl = 0 def hinzufuegen(self, karte): self.kartenListe = self.kartenListe + [karte] self.anzahl = self.anzahl + 1 def wegnehmen(self, karte): if karte in self.kartenListe: i = self.kartenListe.index(karte) del self.kartenListe[i] self.anzahl = self.anzahl - 1 Aufgabe 1: (a) Zeige mit einem geeigneten Python-Dialog, dass ein leichtfertiger Zugriff auf Attribute hier zu unerwünschten Objektzuständen führen kann. (b) Erstelle ein Klassendiagramm, in dem Zugriffsrechte festgelegt sind und benötigte Zugriffsmethoden eingeführt sind. Ergänze die Deklaration der Klasse Kartenhand entsprechend.

52 Übungen from random import randint class Kartenstapel(object): def __init__(self): self.kartenListe = ['X-A', 'X-K', 'X-D', 'X-B', 'X-10', 'X-9', 'X-8', 'X-7', 'P-A', 'P-K', 'P-D', 'P-B', 'P-10', 'P-9', 'P-8', 'P-7', 'H-A', 'H-K', 'H-D', 'H-B', 'H-10', 'H-9', 'H-8', 'H-7', 'K-A', 'K-K', 'K-D', 'K-B', 'K-10', 'K-9', 'K-8', 'K-7'] def mischen(self): neueListe = [] aktuelleAnzahl = len(self.kartenListe) while aktuelleAnzahl > 0: i = randint(0, aktuelleAnzahl-1) neueListe = neueListe + [self.kartenListe[i]] del self.kartenListe[i] self.kartenListe = neueListe def istLeer(self): if len(self.kartenListe) > 0: ergebnis = False else: ergebnis = True return ergebnis def karteZiehen(self): gezogeneKarte = self.kartenListe[0] self.kartenListe = self.kartenListe[1:] gezogeneKarte = None return gezogeneKarte Aufgabe 2: Gegeben ist eine Implementierung der Klasse Kartenstapel: Ergänze Zugriffsmethoden, um einen lesenden und einen schreibenden Zugriff auf das Attribut kartenListe zu ermöglichen.

53 Modularisierung mit Klassen
Teil 4 Modularisierung mit Klassen

54 Das Bausteinprinzip Wenn man die richtigen Bausteine zur Verfügung hat, dann ist es meist recht einfach, das gewünschte System zu entwickeln. Das gilt nicht nur für Systeme im Alltag, diese Aussage trifft auch auf die Entwicklung von Software zu. Wir haben in den vorangegangenen Abschnitten Programme zu Kartenspielen entwickelt. Dabei war es äußerst hilfreich, auf Klassen als fertige Softwarebausteine zurückgreifen zu können. Wir schauen uns hier noch diese Vorgehensweise genauer an. Insbesondere geht es um die Frage, wie eine Klasse aufbereitet werden sollte, damit sie von einem Benutzer direkt als Baustein verwendet werden kann.

55 Verwendung einer Klasse
Ein Nutzer der Klasse Kartenstapel hat das folgende Testprogramm geschrieben. from kartenspiel import Kartenstapel # Testprogramm kartenstapel = Kartenstapel() kartenstapel.mischen() while not kartenstapel.istLeer(): kartenstapel.karteZiehen() karte = kartenstapel.getGezogeneKarte() print(karte) Schnittstelle zur Klasse Nutzung der Klasse Aufgabe: Über welche Informationen muss der Nutzer verfügen, um ein solches Testprogramm schreiben zu können?

56 Verwendung einer Klasse
Der Entwickler der Klasse Kartenstapel veröffentlicht das folgende Klassendiagramm: Klassendiagramm Aufgabe: Welche Informationen über die Klasse Kartenstapel findet man hier? Welche zur Nutzung der Klasse benötigten Informationen sind hier nicht dokumentiert.

57 Verwendung einer Klasse
# # Kartenstapel from random import randint class Kartenstapel(object): __slots__ = ('kartenListe') def __init__(self): """ Die Methode __init__ erzeugt ein Kartenstapel-Objekt. Die 32 Karten werden hier in einer festen Reihenfolge in kodierter Form vorgegeben: 'X-A' (Kreuz Ass), ..., 'K-7' (Karo 7) self.kartenListe = [ 'X-A', 'X-K', 'X-D', 'X-B', 'X-10', 'X-9', 'X-8', 'X-7', 'P-A', 'P-K', 'P-D', 'P-B', 'P-10', 'P-9', 'P-8', 'P-7', 'H-A', 'H-K', 'H-D', 'H-B', 'H-10', 'H-9', 'H-8', 'H-7', 'K-A', 'K-K', 'K-D', 'K-B', 'K-10', 'K-9', 'K-8', 'K-7' ] Python-Docstring Implementierung mit Schnittstellenbeschreibung

58 Verwendung einer Klasse
>>> help(Kartenstapel) Help on class Kartenstapel in module __main__: class Kartenstapel(builtins.object) | Methods defined here: | | __init__(self) | Die Methode __init__ erzeugt ein Kartenstapel-Objekt. | Die 32 Karten werden hier in einer festen Reihenfolge | in kodierter Form vorgegeben: | 'X-A' (Kreuz Ass), ..., 'K-7' (Karo 7) | getKartenListe(self) | Die noch auf den Kartenstapel befindlichen Karten werden | als Liste von Karten zurückgegeben. | istLeer(self) | Die Methode liefert als Ergebnis True / False, | falls der Kartenstapel leer / nicht leer ist. | | Data descriptors defined here: | kartenListe Zugriff auf die Schnittstellenbeschreibung

59 Fachkonzept - Modularisierung
Modularisierung ist ein Prinzip, nach dem viele Systeme entwickelt werden. Die Idee besteht darin, das Gesamtsystem nach dem Baukastenprinzip aus Einzelbausteinen (den sogenannten Modulen) zusammenzusetzen. "Unsere Partyzelte können in verschiedenen Größen aufgebaut werden. Da die Partyzelte und Festzelte aus Modulen bestehen, ist es sehr einfach, sie zu erweitern. Die Abbildung zeigt ein mögliches Kombinationsbeispiel der Module." Ein Softwaremodul ist eine in sich abgeschlossene Programmeinheit, die man vielfältig bei Problemlösungen einsetzen kann. Grundidee der objektorientierten Modularisierung ist es, solche Softwaremodule als Klassen zu konzipieren. Wir werden uns in diesem Abschnitt intensiver mit Problemen auseinander setzen, die bei der Verwendung von Klassen als Softwarebausteine entstehen.

60 Fachkonzept - Schnittstelle
Die Schnittstelle einer Klasse liefert alle Informationen, die man benötigt, um die Klasse benutzen zu können. Hierzu gehört eine genaue Beschreibung aller öffentlichen Attribute und Methoden der Klasse. Für jedes Attribut benötigt man den erwarteten Datentyp, für jede Methode die Signatur (d. h. die genaue Festlegung der Parametertypen und bei Funktionen des Rückgabetyps) und eine Verhaltensbeschreibung. # # Kartenstapel - Schnittstellenbeschreibung class Kartenstapel(object): __slots__ = ('kartenListe') def __init__(self): """ Die Methode __init__ erzeugt ein Kartenstapel-Objekt. Die 32 Karten werden hier in einer festen Reihenfolge in kodierter Form vorgegeben: 'X-A' (Kreuz Ass), ..., 'K-7' (Karo 7)

61 Modulimport in Python # Baustein importieren
from spielkarten import Kartenstapel, Kartenhaufen # Objekte erzeugen und verwenden kartenstapel = Kartenstapel() kartenstapel.mischen() meinKartenhaufen = Kartenhaufen() while meinKartenhaufen.getWert() < 18: karte = kartenstapel.gibObersteKarte() print(karte) meinKartenhaufen.hinzufuegen(karte) print(meinKartenhaufen.getWert()) import spielkarten # Testprogramm kartenstapel = spielkarten.Kartenstapel() kartenstapel.mischen() meinKartenhaufen = spielkarten.Kartenhaufen() while meinKartenhaufen.getWert() < 18: karte = kartenstapel.gibObersteKarte() print(karte) meinKartenhaufen.hinzufuegen(karte) print(meinKartenhaufen.getWert()) # Baustein importieren from spielkarten import * # Objekte erzeugen und verwenden ... Die Namen „Kartenstapel„ und „Kartenhaufen“ werden in den aktuellen Namensraum übernommen.

62 Übungen from random import randint class Lottogeraet(object):
def __init__(self): # erzeugt e. Obj. z. Simulation e. Lottogeraets self.geraetVorbereiten() def geraetVorbereiten(self): # fuellt das Lottogeraet mit Kugeln von 1..49 # leert den Behaelter der gezogenen Kugeln self.vorhandeneKugeln = list(range(1, 50)) self.gezogeneKugeln = [] def kugelZiehen(self): # zieht ei. Kugel aus den noch vorhand. Kugeln # entfernt diese Kugel aus dem Kugelbehaelter # legt d. Kugel i. Behaelter d. gezog. Kugeln ab Aufgabe 1: Zur Simulation von Lotto-Ziehungen wird hier eine Klasse Lottogeraet bereitgestellt. Du findest eine Implementierung dieser Klasse in der Datei lotto.py. (a) Teste die Klasse mit einem einfachen Testprogramm, das alle Methoden der Klasse benutzt. (b) Löse mit Hilfe der Klasse folgendes Problem: Wie oft kommt deine Lieblingszahl (z.B. die 13) in 1000 Lottoziehungen vor?

63 Übungen class Kartenhand(object): def __init__(self, kartenGegeben):
self.kartenListe = kartenGegeben self.anzahl = len(self.kartenListe) def existiertKarte(self, karte): if karte in self.kartenListe: ergebnis = True else: ergebnis = False return ergebnis def hinzufuegen(self, karte): if not self.existiertKarte(karte): self.kartenListe = self.kartenListe + [karte] self.anzahl = self.anzahl + 1 def wegnehmen(self, karte): if self.existiertKarte(karte): i = self.kartenListe.index(karte) del self.kartenListe[i] self.anzahl = self.anzahl - 1 Aufgabe 2: Betrachte die Klasse Kartenhand. (a) Ergänze zunächst geeignete Zugriffsmethoden für die Attribute der Klasse. (b) Ergänze die Implementierung um eine Schnittstellenbeschreibung, so dass die Klasse benutzt werden kann, ohne dass man sich die Implementierungsdetails anschauen muss.

64 Übungen from random import randint class Lottogeraet(object):
def __init__(self): # erzeugt e. Obj. z. Simulation e. Lottogeraets self.geraetVorbereiten() def geraetVorbereiten(self): # fuellt das Lottogeraet mit Kugeln von 1..49 # leert den Behaelter der gezogenen Kugeln self.vorhandeneKugeln = list(range(1, 50)) self.gezogeneKugeln = [] def kugelZiehen(self): # zieht ei. Kugel aus den noch vorhand. Kugeln # entfernt diese Kugel aus dem Kugelbehaelter # legt d. Kugel i. Behaelter d. gezog. Kugeln ab Aufgabe 3: Betrachte noch einmal die Klasse Lottogeraet zur Simulation eines Lottogeräts (siehe lotto.py). Ziel ist es, die Implementierng der Klasse Lottogeraet so abzuändern, dass die vorhandenen bzw. gezogenen Kugeln mit Hilfe von Ankreuzfeldern (implementiert mit Listen mit 49 Wahrheitswerten) verwaltet werden. Am Verhalten der Methoden soll sich dabei aber nichts ändern. (a) Entwickle eine passende Implementierung. Benutze zum Testen das Testprogramm aus Aufgabe 1. (b) Was muss man nach Veränderungen in der Implementierung an der Schnittstellenbeschreibung ändern?

65 Teil 5 Vererbung

66 Kartenstapel als Stapel
Stapel werden im Alltag benutzt, wenn man Gegenstände nach dem LIFO-Prinzip verwalten möchte. LIFO bedeutet dabei "last in, first out" bzw. "wer zuletzt kommt, wir als erstes bearbeit". Kartenstapel sind spezielle Stapel, bei denen Karten nach dem LIFO-Prinzip verwaltet werden. Kartenstapel weisen zusätzliche Besonderheiten auf. Die Karten eines Kartenstapels möchte man auch mischen können. Zielsetzung: Wir werden die Klasse Kartenstapel im Folgenden neu konzipieren. Wir werden dabei ausnutzen, dass Kartenstapel als spezielle Stapel aufgefasst werden können.

67 Stapel Zur Realisierung des LIFO-Prinzips benötigt man Operationen, um ein neues Element oben auf dem Stapel abzulegen und um das oberste Element vom Stapel zu entfernen.

68 Stapel Aufgabe: Implementiere die Klasse Stapel und teste sie sorgfältig. Stapel(pListe): erzeugt einen Stapel mit einer Ausgangsbelegung isEmpty(): überprüft, ob der Stapel Elemente enthält und liefert als Ergebnis einen Wahrheitswert zurück push(element): ein übergebenes Element wird oben auf den Stapel gelegt pop(): das oberste Element des Stapels wird entfernt und als Ergebnis zurückgeliefert (sofern der Stapel Elelente hat) top(): iefert das oberste Element des Stapels (falls ein solches existiert), entfernt es aber nicht aus dem Stapel

69 Kartenstapel als spezieller Stapel
Die Klasse Kartenstapel lässt sich jetzt leicht als Erweiterung der Klasse Stapel gewinnen. Die Idee ist hierbei, das Rad nicht noch einmal neu zu erfinden, sondern die bereits vorhandenen Funktionalitäten zu nutzen und gegebenenfalls zu erweitern oder auch abzuändern. Das folgende Klassendiagramm verdeutlicht diesen Erweiterungsprozess.

70 Kartenstapel als spezieller Stapel
Die Klasse Stapel sieht bereits einige Methoden zur Realisierung eines Kartenstapels vor. So kann die Methode pop benutzt werden, um eine Karte vom Stapel zu ziehen. Mit der Methode isEmpty kann man überprüfen, ob noch Karten auf dem Stapel liegen. Noch nicht realisiert ist dagegen das Mischen der Karten. Ebenfalls noch nicht realisiert ist die adäquate Initialisierung des Stapel: Bei einem Kartenstapel sollten zunächst alle 32 Spielkarten im Stapel vorkommen.

71 Implementierung from stapel import Stapel from random import randint
class Kartenstapel(Stapel): def __init__(self): self.liste = [ 'X-A', 'X-K', 'X-D', 'X-B', 'X-10', 'X-9', 'X-8', 'X-7', 'P-A', 'P-K', 'P-D', 'P-B', 'P-10', 'P-9', 'P-8', 'P-7', 'H-A', 'H-K', 'H-D', 'H-B', 'H-10', 'H-9', 'H-8', 'H-7', 'K-A', 'K-K', 'K-D', 'K-B', 'K-10', 'K-9', 'K-8', 'K-7' ] def mischen(self): neueListe = [] aktuelleAnzahl = len(self.liste) while aktuelleAnzahl > 0: i = randint(0, aktuelleAnzahl-1) neueListe = neueListe + [self.liste[i]] del self.liste[i] self.liste = neueListe

72 Implementierung from kartenstapel import Kartenstapel # Test
kartenstapel = Kartenstapel() kartenstapel.mischen() while not kartenstapel.isEmpty(): obersteKarte = kartenstapel.pop() print(obersteKarte)

73 Fachkonzept - Vererbung
Vererbung beschreibt die Vorgehensweise, eine neue Klasse als Erweiterung einer bereits bestehenden Klasse (oder mehrerer bereits bestehender Klassen) zu entwickeln. Die neue Klasse wird auch Subklasse genannt. Die bestehende Klasse wird Basisklasse oder Superklasse genannt. Übernehmen, ergänzen und überschreiben Beim Vererben übernimmt die Subklasse die Attribute und Methoden der Basisklasse. Eine übernommene Methode kann dabei überschrieben (d. h. neu definiert) werden. Die Subklasse kann dann noch zusätzliche Attribute und Methoden ergänzen.

74 Fachkonzept - Vererbung
Vorteile von Vererbung: Man kann Methoden der Basisklasse(n) nutzen. Nachteile von Vererbung: Eine Subklasse ist keine autonome Einheit, die ohne die Basisklasse(n) verwendet werden kann. Hinweis: Wir werden Vererbung im Folgenden bei der Entwicklung objektorientierter Modelle eher selten nutzen.


Herunterladen ppt "Konzepte objektorientierter Programmierung: Objekte und Klassen"

Ähnliche Präsentationen


Google-Anzeigen