Die Präsentation wird geladen. Bitte warten

Die Präsentation wird geladen. Bitte warten

Konzepte objektorientierter Programmierung

Ähnliche Präsentationen


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

1 Konzepte objektorientierter Programmierung
Klaus Becker 2009

2 Oestereich: Objektorientierte Software-Entwicklung
Objektorientierung "Objektorientierung ist die derzeitige Antwort auf die gestiegene Komplexität der Softwareentwicklung." Oestereich: Objektorientierte Software-Entwicklung

3 Teil 1 Objekte

4 Verwaltung von Bankkonten
Ziel ist es, ein System zur Verwaltung von Bankkonten zu entwickeln. Dieses System soll recht einfach gestaltet werden, um es leicht durchschaubar zu halten. Aus diesem Grund werden wir auf viele Aspekte eines realen Bankkontenverwaltungssystem verzichten. S Konto-Nr Freunde des Burggymnasiums Kontoauszug Blatt 342 Datum Erläuterung Betrag Miete der Fruchthalle - Sommerkonzert Spende eines ehemaligen Schülers Zuschuss zum Whiteboard Kontostand in EUR,

5 Verwaltung von Bankkonten
Wesentliche zu verwaltende Daten erkennt man auf einem Kontoauszug. Kontonummer Kontoinhaber S Konto-Nr Freunde des Burggymnasiums Kontoauszug Blatt 342 Datum Erläuterung Betrag Miete der Fruchthalle - Sommerkonzert Spende eines ehemaligen Schülers Zuschuss zum Whiteboard Kontostand in EUR, auszahlen einzahlen auszahlen Kontostand Ein Bankkonto hat eine bestimmte Kontonummer (und einen Kontoinhaber - von dem wir vorerst einmal absehen). Ein Bankkonto hat zudem einen bestimmten Stand - das ist der Geldbetrag, der aktuell auf dem Konto verfügbar ist. Von einem Bankkonto kann man Geldbeträge auszahlen, man kann aber Geldbeträge auf ein Konto einzahlen.

6 Objektorientierter Modellierungsansatz
So wie die zu verwaltende Welt aus Objekten - hier Konten - besteht, so soll das Verwaltungssystem aus Softwareobjekten aufgebaut werden. Softwareobjekt S Konto-Nr Freunde des Burggymnasiums Kontoauszug Blatt 342 Datum Erläuterung Betrag Miete der Fruchthalle - Sommerkonzert Spende eines ehemaligen Schülers Zuschuss zum Whiteboard Kontostand in EUR,

7 Softwareobjekt in Aktion
Wenn man das Programm konto.py ausführt, dann lässt sich folgender Python-Dialog führen. Probiere das einmal aus. >>> konto = Konto(234126) >>> konto.nr 234126 >>> konto.stand >>> konto.stand = 2380.0 >>> konto.auszahlen(450.0) 1930.0 >>> konto.einzahlen(1000.0) 2930.0 >>> konto.auszahlen(800.0) 2130.0

8 Objekte Ein Objekt ist eine Einheit, die Daten mit Hilfe von Attributen verwalten und Operationen zur Verarbeitung der verwalteten Daten mit Hilfe von Methoden ausführen kann. 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

9 Objekte Zugriff auf Attribute: Objekt objekt.attribut
konto.stand = Aktivierung von Methoden: objekt.methode Attribute - Attributwerte konto.einzahlen(1000.0) Ausführung einer Methode

10 Übungen Aufgabe 1 (siehe www.inf-schule.de 1.12.1.4)
Lade die Datei wuerfel.txt herunter (benenne sie in wuerfel.py um) und führe einen Python-Dialog analog zum folgenden: >>> w = Wuerfel() >>> w.augen 1 >>> w.werfen() 6 (a) Was leistet das Attribut augen des Objekts w, was die Methode werfen()? (b) Beschreibe den gezeigten Ablauf mit Hilfe von Objektdiagrammen.

11 Teil 2 Klassen

12 Ein Bauplan für Konto-Objekte
class Konto(object): def __init__(self, nummer): self.nr = nummer self.stand = 0 def einzahlen(self, betrag): self.stand = self.stand + betrag def auszahlen(self, betrag): # ... >>> k1 = Konto(5) >>> k1.nr 5 >>> k1.stand >>> k1.einzahlen(100.0) 100.0 Aufgabe 1: Analysiere diese Klassendeklaration und ergänze den fehlenden Teil # .... Überprüfen kannst du deinen Lösungsvorschlag, indem du die Klassendeklaration unter einem geeigneten Namen (z. B. konto.py) abspeicherst und ausführst. Wenn du alles richtig gemacht hast, dann sollte z. B. der oben gezeigte Python-Dialog möglich sein.

13 Ein Bauplan für Konto-Objekte
class Konto(object): def __init__(self, nummer): self.nr = nummer self.stand = 0 def einzahlen(self, betrag): self.stand = self.stand + betrag def auszahlen(self, betrag): # ... >>> k1 = Konto(5) >>> k1.einzahlen(1000.0) >>> k2 = Konto(8) >>> ... Aufgabe 2: Versuche auch einmal, mehrere Konto-Objekte zu erzeugen. Überweise mit passenden Methoden (Euro) vom Konto mit der Kontonummer 5 auf das Konto mit der Kontonummer 8.

14 Klassen 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

15 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 viele 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.

16 Klassendeklaration in Python
Klassenname Oberklasse Schlüsselwort Doppelpunkt class Konto(object): def __init__(self, nummer): self.nr = nummer self.stand = 0 def einzahlen(self, betrag): self.stand = self.stand + betrag def auszahlen(self, betrag): self.stand = self.stand - betrag Einrückung Konstruktor Attribute Attribute Methode Methode Referenz auf Objekt

17 Objekterzeugung in Python
class Konto(object): def __init__(self, nummer): self.nr = nummer self.stand = 0 def einzahlen(self, betrag): self.stand = self.stand + betrag def auszahlen(self, betrag): self.stand = self.stand - betrag Klassendeklaration >>> k1 = Konto(5) >>> k2 = Konto(8) >>> k1.nr 5 >>> k1.stand >>> k2.nr 8 >>> k2.stand >>> k1.__dict__ {'nr': 5, 'stand': 0} >>> k2.__dict__ {'nr': 8, 'stand': 0} >>> k = Konto(5) >>> k.stand 0.0 >>> del k Traceback (most recent call last): File ... NameError: name 'k' is not defined >>> Erzeugung eines Objekts Vernichtung eines Objekts Inspektion eines Objekts

18 Übungen Aufgabe 1 (siehe www.inf-schule.de 1.12.2.5)
Gegeben ist eine Implementierung der Klasse Wuerfel(): from random import randint class Wuerfel(object): def __init__(self): self.augen = 1 def werfen(self): self.augen = randint(1, 6) Erzeuge drei Objekte der Klasse Wuerfel und würfele hiermit solange, bis mindestens einer der Würfel eine 6 liefert.

19 Übungen Aufgabe 2 (siehe www.inf-schule.de 1.12.2.5)
Gegeben ist das folgende Klassendiagramm zur Klasse Bruch: Was soll mit einem Objekt der Klasse Bruch beschrieben werden? Entwickle eine geeignete Implementierung und teste sie mit einem Python-Dialog.

20 Übungen Aufgabe 3 (siehe www.inf-schule.de 1.12.2.5)
Wenn man modulo einer vorgegebenen Zahl (man nennt sie auch Modul) zählt, dann bildet man jeweils den Rest bei der Division durch die vorgegebene Zahl. Betrachte als Beispiel die vorgegebene Zahl (Modul) 5. Wenn man modulo 5 zählt, dann geht das so: 0 modulo 5, 1 modulo 5, 2 modulo 5, 3 modulo 5, 4 modulo 5, 5 modulo 5, 6 modulo 5, ... Berechnet man jeweils die Reste, dann ergibt das folgende die Zahlenfolge 0, 1, 2, 3, 4, 0, 1, ... . Wenn man modulo einer vorgegebenen Zahl n zählt, dann ergibt das also die Zahlenfolge 0, 1, ..., (n-1), 0, 1, .... Konzipiere eine Klasse ModuloZaehler (mit einem Klassendiagramm), die Python-Dialoge wie den folgenden ermöglicht. Implementiere die Klasse und teste sie mit geeigneten Python-Dialogen. >>> z = ModuloZaehler(3) >>> z.modul 3 >>> z.stand >>> z.weiterzaehlen() 1 2 >>> z.zurueckzaehlen() >>> z.nullsetzen()

21 Übungen Aufgabe 5 (siehe www.inf-schule.de 1.12.2.5)
Die Klasse Schlange kann man verwenden, um Warteschlangen zu simulieren. Erläutere, was die Methoden der Klasse Schlange bewirken. Verdeutliche deine Erläuterungen jeweils mit einem geeigneten Python-Protokoll. class Schlange(object): def __init__(self): self.liste = [] def istLeer(self): if self.liste == []: return True else: return False def mitLetztem(self, element): self.liste = self.liste + [element] def ohneErstes(self): if not self.istLeer(): self.liste = self.liste[1:] ... ... def anzahlElemente(self): return len(self.liste) def getSchlange(self): return self.liste def setSchlange(self, liste): self.liste = liste

22 Übungen Aufgabe 6 (siehe www.inf-schule.de 1.12.2.5)
Die folgende Deklaration des Konstruktors erlaubt es, Objekte flexibel mit Anfangswerten zu versehen: >>> k1 = Konto() >>> k1.nr >>> k1.stand >>> k2 = Konto(1) >>> k2.nr 1 >>> k2.stand >>> k3 = Konto(2, ) >>> k3.nr 2 >>> k3.stand 1000.0 >>> k4 = Konto(betrag=400.0) >>> k4.nr >>> k4.stand 400.0 class Konto(object): def __init__(self, nummer=0, betrag=0): self.nr = nummer self.stand = betrag def einzahlen(self, betrag): self.stand = self.stand + betrag def auszahlen(self, betrag): self.stand = self.stand - betrag Erkläre, wie die jeweiligen Attributwerte der Objekte zustande kommen.

23 Verwaltung von Objekten
Teil 3 Verwaltung von Objekten

24 Objekte und ihre Identität
>>> k1 = Konto(3) >>> k1 <__main__.Konto object at 0x0135D670> >>> id(k1) >>> hex( ) '0x135d670' >>> k2 = Konto(4) >>> id(k2) Aufgabe: Was verbirgt sich wohl hinter der Identitätsnummer eines Objekts? Prüfe mit geeigneten Python-Dialogen, ob sich die Identitätsnummer eines Objekts ändert, wenn sich der Zustand eines Objekts beim Ausführen einer Methode ändert. Python-Dialog

25 Konto kopieren? >>> k1 = Konto(6) >>> k2 = k1
>>> k1.stand ??? >>> k2.stand >>> k2.einzahlen(100.0) >>> k2 = Konto(7) >>> Aufgabe: Stell Vermutungen auf, was anstelle der drei Fragezeichen jeweils steht. Teste, ob deine Vermutungen stimmen. Kannst du dir die Ergebnisse erklären? Benutze auch den id-Operator, um Einsicht über die verwalteten Objekte zu erhalten. Python-Dialog

26 Identität von Objekten
(Daten-) Objekte haben - analog zu Objekten unserer Lebenswelt - ebenfalls eine Identität. Zur eindeutigen Identifizierung werden sie mit Identitätsnummern versehen. Verschiedene Objekte unterscheiden sich in ihrer Identitätsnummer. Sie können aber durchaus denselben Objektzustand haben. Ein Objekt behält während seiner Lebensdauer immer die einmal vergebene Identitätsnummer. Auch wenn sich der Zustand des Objekts verändert, so bleibt doch die Identitätsnummer des Objekts bestehen. Häufig verwendet hierzu man eine Adresse im Speicher des Rechners als Identitätsnummer. Die Identitätsnummer eines Objekts zeigt dann auf den Speicherbereich, in dem die Daten des Objekts abgelegt sind. Diese Identifikation von Objekten durch eine Lokalisierung im Speicher setzt natürlich voraus, dass Objekte im Speicher nicht hin und her wandern, sondern dass der einmal zugeteilte Speicherbereich während der Lebensdauer eines Objekts bestehen bleibt. Wir gehen im Folgenden von dieser Vorstellung aus.

27 Zeiger / Referenzen Eine Variable ist ein Name, der (in der Regel) mit einem Objekt verknüpft ist. Wenn eine Variable ein (Daten-) Objekt verwaltet, dann verwaltet es die Speicheradresse (bzw. Identitäsnummer) dieses Objekts. Da die Speicheradresse auf das Objekt zeigt bzw. das Objekt referenziert, nennt man eine solche Adresse auch Zeiger bzw. Referenz und die Variable zur Verwaltung der Adresse Zeigervariable bzw. Referenzvariable.

28 Zuweisungen bei Zeigervariablen
k1 = Konto(6) k2 = k1 k2.einzahlen(100.0) k2 = Konto(7)

29 Unveränder-bares Objekt
Objekte in Python Veränderbares Objekt Unveränder-bares Objekt from konto import * def null(konto): print(id(konto)) konto.stand = 0.0 k = Konto(9) k.einzahlen(100.0) print(k.stand) print(id(k)) null(k) def null(zahl): print(id(zahl)) zahl = 0.0 z = 100.0 print(z) print(id(z)) null(z) kein Seiteneffekt Seiteneffekt Python unterscheidet zwischen veränder-baren und unveränderbaren Objekten.

30 Übungen Aufgabe 1 (siehe www.inf-schule.de 1.12.3.5)
Wenn man den Objektbezeichner vom Python-Interpreter auswerten lässt, dann wird der vom Bezeichner verwaltete Wert angezeigt. Warum zeigt der Python-Dialog, dass hier Zeiger verwaltet werden? class Konto(object): def __init__(self, nummer): self.nr = nummer self.stand = 0 def einzahlen(self, betrag): self.stand = self.stand + betrag def auszahlen(self, betrag): self.stand = self.stand - betrag >>> k1 = Konto(6) >>> k2 = k1 >>> k1 <__main__.Konto object at 0x01DA7F10> >>> k2 >>> k2 = Konto(8) <__main__.Konto object at 0x01DB5CB0>

31 Übungen Aufgabe 2 (siehe www.inf-schule.de 1.12.3.5)
Jedes Objekt wird zur Identifierung mit einer eindeutigen Identitätsnummer versehen. Mit Hilfe des id-Operators lässt sich diese Identitätsnummer in Python ermitteln. Was zeigt der abgebildete Python-Dialog? class Konto(object): def __init__(self, nummer): self.nr = nummer self.stand = 0 def einzahlen(self, betrag): self.stand = self.stand + betrag def auszahlen(self, betrag): self.stand = self.stand - betrag >>> k1 = Konto(6) >>> k2 = k1 >>> id(k1) >>> id(k2) >>> k2 = Konto(8) >>> id(k2)

32 Übungen Aufgabe 3 (siehe www.inf-schule.de 1.12.3.5)
Die Funktion mitNeuemErsten soll dazu dienen, in einer Liste das erste Element auszutauschen. Vegleiche die beiden folgenden Implementierungen und erkläre das unterschiedliche Verhalten. def mitNeuemErsten(liste, element): liste[0] = element return liste L = [1, 2, 3] M = mitNeuemErsten(L, 0) print(L) print(M) def mitNeuemErsten(liste, element): hilf = [element] + liste[1:] return hilf L = [1, 2, 3] M = mitNeuemErsten(L, 0) print(L) print(M)

33 Modularisierung und Datenkapselung
Teil 4 Modularisierung und Datenkapselung

34 Implementierung der Klasse
Konto überziehen Ein Konto soll höchstens um 1000 Euro überzogen werden dürfen. class Konto(object): def __init__(self, nummer): self.nr = nummer self.stand = 0 self.minimum = def einzahlen(self, betrag): self.stand = self.stand + betrag def auszahlen(self, betrag): if self.stand - betrag >= self.minimum: self.stand = self.stand - betrag else: print("Auszahlung nicht möglich!") >>> k = Konto(9) >>> k.stand = 600.0 >>> k.stand 600.0 >>> auszahlungsbetrag = >>> k.stand = k.stand - auszahlungsbetrag Nutzung der Klasse Implementierung der Klasse Aufgabe 1: Warum ist dieser Dialog nicht im Sinne des Bankkontenverwaltungssystems?

35 Schnittstelle zur Klasse
Konto überziehen Die Entwickler der Klasse Konto veröffentlichen folgende Schnittstelle dieser Klasse: from konto import Konto k = Konto(9) # Testlauf k.einzahlen(600.0) print(k.getStand()) auszahlungsbetrag = k.auszahlen(auszahlungsbetrag) Schnittstelle zur Klasse Nutzung der Klasse Aufgabe 2: Warum macht es hier Sinn, die Attribute der Klasse Konto nicht zu veröffentlichen und eine Veränderung von Attributwerten nur über veröffentlichte Merhoden zu erlauben? Aufgabe 3: Im Testprogramm wird die Methode getStand benutzt, die in der Schnittstelle vorgesehen ist. Was soll diese Methode leisten? Ergänze die oben gezeigte Implementierung der Klasse Konto um die noch fehlenden Methoden und führe das Testprogramm aus.

36 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 Einheit, die man vielfältig bei Problem-lösungen einsetzen kann. Es reicht dabei zu wissen, welche Operationen die Einheit dem Benutzer zur Verfügung stellt. Wie die Operationen programmiert sind, muss man dagegen nicht wissen. Grundidee der objektorientierten Modularisierung ist es, Softwaremodule als Klassen zu konzipieren .

37 Modularisierung in Python
from konto import Konto k = Konto(9) # Testlauf k.einzahlen(600.0) print(k.getStand()) auszahlungsbetrag = k.auszahlen(auszahlungsbetrag) import konto k = konto.Konto(9) # Testlauf k.einzahlen(600.0) print(k.getStand()) auszahlungsbetrag = k.auszahlen(auszahlungsbetrag) from konto import * k = Konto(9) # Testlauf k.einzahlen(600.0) print(k.getStand()) auszahlungsbetrag = k.auszahlen(auszahlungsbetrag) Der Name "Konto" wird in den aktuellen Namensraum übernommen.

38 Geheimnisprinzip / Datenkapselung
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. Bei der objektorientierten Software-Entwicklung geht man völlig analog vor. Nach dem Geheimnisprinzip werden die internen Daten eines Objekts (die in der Regel über Attribute verwaltet werden) so verborgen, dass ein direkter Zugriff hierauf nicht möglich ist. Jeder Zugriff auf interne Daten und jede Veränderung von internen Daten darf nur über spezielle, hierfür vorgesehene Methoden erfolgen. Man nennt diese Vorgehensweise auch Datenkapselung.

39 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.

40 Zugriffsrechte in Python
class Konto(object): def __init__(self, nummer): self.__nr = nummer self.__stand = 0 self.__minimum = def einzahlen(self, betrag): self.__stand = self.__stand + betrag def auszahlen(self, betrag): if self.__stand - betrag >= self.__minimum: self.__stand = self.__stand - betrag else: print("Auszahlung nicht möglich!") def getStand(self): return self.__stand def setStand(self, stand): if stand >= self.__minimum: self.__stand = stand print("Initialisierung nicht möglich!") # ... Ein Attribut / eine Methode wird in Python zu einem privaten Attribut, wenn der Attributname mit zwei Unterstrichen beginnt und nicht mit Unterstrichen endet. Beginnt der Attributname / Methodenname nicht mit einem Unterstrich, so ist das Attribut öffentlich.

41 Datenkapselung in Python
>>> k = Konto(3) >>> k.__stand Traceback (most recent call last): File ... AttributeError: 'Konto' object has no attribute '__stand' >>> k.__dict__ {'_Konto__minimum': , '_Konto__nr': 3, '_Konto__stand': 0} >>> k._Konto__stand Wie erwartet kann man auf das private Attribut __stand des neu erzeugten Objekts k nicht zugreifen. Python meldet als Fehler, dass es kein Attribut __stand gibt. Der Aufruf k.__dict__ verrät, woran das liegt. Ein Aufruf wie k.__dict__ listet sämtliche Attribute mit den zugehörigen Attributwerten des betreffenden Objekts auf. Interessant ist hier, dass sich das private Attribut __stand hinter einem anderen Namen versteckt. Wenn man weiß, wie der neue Name - hier _Konto__stand - gebildet wird, dann kann man durchaus 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.

42 Datenkapselung in Python
>>> k = Konto(3) >>> k.__stand Traceback (most recent call last): File ... AttributeError: 'Konto' object has no attribute '__stand' >>> k.__dict__ {_Konto__minimum': , '_Konto__nr': 3, '_Konto__stand': 0} >>> k.__stand = 100.0 100.0 {_Konto__minimum': , '_Konto__nr': 3, '_Konto__stand': 0, '__stand': 100.0} Ein erster Zugriff auf das private Attribut __stand scheitert. Dann aber ist es - entgegen aller Zugriffslogik - scheinbar möglich, dem privaten Attribut __stand einen Wert zuzuweisen. Der Aufruf k.__dict__ erklärt erst, was hier passiert ist. Neben dem privaten Attribut __stand, das sich hinter dem neuen Namen _Konto__stand versteckt, gibt es noch öffentliches Attribut __stand, auf das man direkt zugreifen kann. Wir werden im Folgenden bei der Implementierung von Klassen in Python keine Attribute als private Attribute deklarieren. In der Regel werden wir auch keine Zugriffsmethoden einführen und nutzen. Nur in begründeten Ausnahmefällen werden wir von dieser Vereinbarung abweichen.

43 Schnittstellen 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. Konto(nummer: int) nachher: Ein Objekt der Klasse Konto ist erzeugt. Der Wert des Attributs nr entspricht dem übergebenen Wert des Parameters nummer, der Wert des Attributs stand beträgt 0, der Wert des Attributs minimum beträgt auszahlen(betrag: float) vorher: Das Konto-Objekt hat einen beliebigen Zustand. nachher: Der Wert des Attributs stand des Konto-Objekts ist um den übergebenen Wert des Parameters betrag reduziert.

44 Übungen Aufgabe 1 (siehe www.inf-schule.de 1.12.4.8)
Zur Klasse Wuerfel soll folgende Implementierung in einer Datei wuerfel.py abgespeichert sein: from random import randint class Wuerfel(object): def __init__(self): self.augen = 1 def werfen(self): self.augen = randint(1, 6) (a) Was leistet das folgende Programm, das das Modul Wuerfel als Baustein benutzt? (b) Es soll getestet werden, wie oft man drei Würfel werfen muss, bis mindestens einer eine 6 liefert. Entwickle ein geeignetes Simulationsprogramm, das die Klasse Wuerfel als Baustein benutzt. from wuerfel import * # Würfelprogramm w = Wuerfel() w.werfen() versuche = 1 while w.augen != 6: versuche = versuche + 1 print("Versuche:", versuche)

45 Übungen >>> k = Konto(100)
>>> s = Spielzahl() >>> wA = Wuerfel() >>> wB = Wuerfel() >>> wC = Wuerfel() >>> k.abheben(1) >>> k.stand 99 >>> s.setzen(3) >>> s.zahl 3 >>> wA.werfen() >>> wB.werfen() >>> wC.werfen() >>> wA.augen >>> wB.augen 6 >>> wC.augen 2 >>> k.einzahlen(2) 101 Aufgabe 2 (siehe ) Folgende Klassen sollen als Bausteine zur Simulation des Spiels "chuck a luck" zur Verfügung gestellt werden: (a) Implementiere diese Klassen. Mit Hilfe dieser Bausteine sollen dann Python-Dialoge wie der folgende möglich sein. (b) Mit Hilfe eines Simulationsprogramms soll ermittelt werden, ob das chuck-a-luck-Spiel fair ist.

46 Übungen ... Aufgabe 3 (siehe www.inf-schule.de 1.12.4.8)
def vollstaendigKuerzen(self): # ggT von Zähler und Nenner best. x = self.zaehler y = self.nenner while y > 0: h = x % y x = y y = h ggt = x # kürzen self.kuerzen(ggt) def add(self, b): x1 = self.zaehler x2 = self.nenner y1 = b.zaehler y2 = b.nenner z1 = x1*y2 + x2*y1 z2 = x2*y2 self.zaehler = z1 self.nenner = z2 self.vollstaendigKuerzen() Aufgabe 3 (siehe ) (a) Erstell ein Klassendiagramm und eine Schnittstellenbeschreibung zur Klasse Bruch. (b) Entwickle ein Testprogramm, das die Klasse Bruch als Modul benutzt. class Bruch(object): def __init__(self, z, n): self.zaehler = z self.nenner = n def erweitern(self, k): self.zaehler = self.zaehler * k self.nenner = self.nenner * k def kuerzen(self, k): if (self.zaehler % k == 0) and \ (self.nenner % k == 0): self.zaehler = self.zaehler // k self.nenner = self.nenner // k ... (c) Füge der Klasse Bruch weitere Operationen hinzu und teste diese Erweiterung.

47 Übungen Aufgabe 5 (siehe www.inf-schule.de 1.12.4.8)
Teste die Einbindung folgender Modulimporte und ihre Auswirkung auf den globalen Namensraum. Warum wird bei sehr umfangreichen Modulen empfohlen, die erste oder dritte der oben aufgelisteten Einbindungsvarianten zu benutzen? >>> from random import randint >>> globals() >>> from random import * >>> globals() >>> import random >>> globals()

48 Übungen Aufgabe 6 (siehe www.inf-schule.de 1.12.4.8)
(a) Teste diese Implementierung der Klasse Bruch. Irgend etwas stimmt hier nicht. Findest du den Fehler? Benutze die Operation __dict__() zur Fehlersuche. Erkläre, was hier schiefläuft. (b) Warum ist es so schwierig, Flüchtigkeitsfehler wie den oben gezeigten zu finden? class Bruch(object): def __init__(self, z, n): self.zaehler = z self.nenner = n def erweitern(self, k): self.zahler = self.zaehler * k self.nenner = self.nenner * k def kuerzen(self, k): if (self.zaehler % k == 0) and \ (self.nenner % k == 0): self.zaehler = self.zaehler // k self.nenner = self.nenner // k

49 Teil 5 Beziehungen

50 Verwaltung des Kontoinhabers
Konto-Nr.5 Adriana Müller Kontoauszug Blatt 3 Datum Erläuterung Betrag Handykosten Zuschuss von Oma und Opa Schuhe Kontostand in EUR, Der Kontoinhaber soll jetzt ebenfalls mitverwaltet werden. Hierzu muss das Objektmodell erweitert werden. Mehrere Vorschläge stehen zur Diskussion Aufgabe: Vergleiche die folgenden Vorschläge. Vorschlag 1: Vorschlag 2:

51 Verwaltung des Kontoinhabers
Vorschlag 2: Aufgabe: Welche Nachteile zeigen sich bei Vorschlag 2, wenn es mehrere Konten und mehrere Kunden gibt? Vergleiche Vorschlag 2 mit Vorschlag 3. Vorschlag 3:

52 Verwaltung des Kontoinhabers
class Konto(object): def __init__(self, nummer): self.nr = nummer self.stand = 0.0 self.inhaber = None def einzahlen(self, betrag): self.stand = self.stand + betrag def auszahlen(self, betrag): self.stand = self.stand - betrag class Kunde(object): def __init__(self, name, vorname): self.name = name self.vorname = vorname from konto_kunde import * # Erzeugung der Objekte konto1 = Konto(5) konto2 = Konto(11) konto2.stand = 200.0 kunde1 = Kunde("Müller", "Adriana") kunde2 = Kunde("Meier", "Anatol") konto1.inhaber = kunde2 konto2.inhaber = kunde1 # Ausgaben print("Kontonummer: ", konto1.nr) print("Inhaber(in): ", konto1.inhaber.vorname, \ konto1.inhaber.name) print("Kontostand: ", konto1.stand) print() print("Kontonummer: ", konto2.nr) print("Inhaber(in): ", konto2.inhaber.vorname, \ konto2.inhaber.name) print("Kontostand: ", konto2.stand) Aufgabe: Erkläre, wie die Objektkonstellation aus Vorschlag 3 hier realisiert wird. Stell auch eine Vermutung auf, was das Testprogramm auf dem Bildschirm ausgibt.

53 Beziehung Wenn ein Objekt über einen Zeiger (eine Referenz) Zugriff auf ein anderes Objekt hat, so liegt eine (gerichtete) Beziehung zwischen den Objekten vor. Mit Hilfe eines Aufrufs wie z.B. konto1.inhaber kann das Konto-Objekt konto1 auf Daten des zugeordneten Kunde-Objekts zugreifen, z.B. mit konto1.inhaber.name auf das entsprechende Attribut. Das Konto-Objekt konto1 hat somit Zugriff auf ein Kunde-Objekt, z.B. kunde2. Man sagt auch, dass das Konto-Objekt konto1 in Beziehung zum Kunde-Objekt kunde2 steht. Objektdiagramm Klassendiagramm

54 Beziehungsmuster Muster: Objekt der Klasse A kennt Objekt der Klasse B
Objekt der Klasse A erzeugt Objekt der Klasse B Muster: Objekt der Klasse A kennt Objekt der Klasse B und umgekehrt Muster: Objekt der Klasse A kennt mehrere Objekte der Klasse B

55 Implementierung von Beziehungen
class Konto(object): def __init__(self, nummer): self.nr = nummer self.stand = 0.0 self.inhaber = None def einzahlen(self, betrag): self.stand = self.stand + betrag def auszahlen(self, betrag): self.stand = self.stand - betrag class Kunde(object): def __init__(self, name, vorname): self.name = name self.vorname = vorname from bank0 import * # Erzeugung der Objekte konto1 = Konto(5) konto2 = Konto(11) konto2.stand = 200.0 kunde1 = Kunde("Müller", "Adriana") kunde2 = Kunde("Meier", "Anatol") konto1.inhaber = kunde2 konto2.inhaber = kunde1 Muster: Objekt der Klasse A kennt Objekt der Klasse B

56 Implementierung von Beziehungen
class Konto(object): def __init__(self, nummer): self.nr = nummer self.stand = 0.0 self.inhaber = None def einzahlen(self, betrag): self.stand = self.stand + betrag def auszahlen(self, betrag): self.stand = self.stand - betrag class Kunde(object): def __init__(self, name, vorname): self.name = name self.vorname = vorname self.konto = None from bank1 import * # Erzeugung der Objekte konto1 = Konto(5) konto2 = Konto(11) konto2.stand = 200.0 kunde1 = Kunde("Müller", "Adriana") kunde2 = Kunde("Meier", "Anatol") konto1.inhaber = kunde2 konto2.inhaber = kunde1 kunde1.konto = konto2 kunde2.konto = konto1 Muster: Objekt der Klasse A kennt Objekt der Klasse B und umgekehrt

57 Implementierung von Beziehungen
class Konto(object): def __init__(self, nummer): self.nr = nummer self.stand = 0.0 self.inhaber = None def einzahlen(self, betrag): self.stand = self.stand + betrag def auszahlen(self, betrag): self.stand = self.stand - betrag class Kunde(object): def __init__(self, name, vorname): self.name = name self.vorname = vorname self.konten = [] def kontoHinzufuegen(self, konto): self.konten = self.konten + [konto] from bank2 import * # Erzeugung der Objekte konto1 = Konto(5) konto2 = Konto(11) konto2.stand = 200.0 konto3 = Konto(19) konto3.stand = 150.0 konto4 = Konto(21) konto4.stand = -50.0 kunde1 = Kunde("Müller", "Adriana") kunde2 = Kunde("Meier", "Anatol") konto1.inhaber = kunde2 konto2.inhaber = kunde1 konto3.inhaber = kunde1 konto4.inhaber = kunde1 kunde1.kontoHinzufuegen(konto2) kunde1.kontoHinzufuegen(konto3) kunde1.kontoHinzufuegen(konto4) kunde2.kontoHinzufuegen(konto1) Liste Muster: Objekt der Klasse A kennt mehrere Objekte der Klasse B

58 Implementierung von Beziehungen
class Konto(object): def __init__(self, nummer): self.nr = nummer self.stand = 0.0 self.inhaber = None def einzahlen(self, betrag): self.stand = self.stand + betrag def auszahlen(self, betrag): self.stand = self.stand - betrag class Bank(object): def __init__(self): self.konten = [] self.naechsteKontoNr = 0 def erzeugeKonto(self): konto = Konto(self.maxKontoNr) self.konten = self.konten + [konto] self.naechsteKontoNr = self.naechsteKontoNr + 1 from bank3 import * from random import * # Erzeugung der Objekte bank = Bank() for i in range(8): bank.erzeugeKonto() for konto in bank.konten: konto.einzahlen(float(randint(0, 100))) Muster: Objekt der Klasse A erzeugt Objekte der Klasse B

59 Operationen als Dienste
Objekte können (in aller Regel) bestimmte Operationen mit den von ihnen verwalteten Daten ausführen. Die Ausführung einer Operationen wird als Dienst anderen Objekten zur Verfügung gestellt. Andere Objekte können den zur Verfügung gestellten Dienst dann nutzen. Hier wird also die Anbieter-Nutzer-Sichtweise benutzt. Ein Bank-Objekt bietet z.B. den Dienst ueberweisen an. Ein Konto-Objekt bietet z.B. den Dienst einzahlen an.

60 Interaktion zwischen Objekten
Die Analogien zur Lebenswelt ermöglichen es, die Ausführung objektorientierter Programme in einem Rollenspiel zu verdeutlichen, bei dem Personen die Rolle von Objekten übernehmen. Wenn das Bank-Objekt den Dienst "ueberweisen" ausführt, dann schickt es zunächst eine Nachricht auszahlen(...) an das betreffende Konto-Objekt und anschließend eine Nachricht einzahlen(...) an das andere betreffende Konto-Objekt. Das Bank-Objekt interagiert also hier mit zwei Konto-Objekten. Dies ist deshalb möglich, weil das Bank-Objekt gemäß Klassendiagramm oben in Beziehung zu den Konto-Objekten steht.

61 Interaktion zwischen Objekten
Wenn ein Objekt den Dienst eines anderen Objekt nutzen will, dann schickt es ihm eine Nachricht. Das Senden einer Nachricht bedeutet, ein Objekt zu veranlassen, eine seiner als Dienste zur Verfügung gestellten Operationen. Das Versenden von Nachrichten wird als Interaktion zwischen Objekten gedeutet. Voraussetzung für eine Interaktion zwischen Objekten ist, dass diese miteinander in Beziehung stehen. Sequenzdiagramm Wenn das Bank-Objekt den Dienst "ueberweisen" ausführt, dann schickt es zunächst eine Nachricht auszahlen(...) an das betreffende Konto-Objekt und anschließend eine Nachricht einzahlen(...) an das andere betreffende Konto-Objekt. Das Bank-Objekt interagiert also hier mit zwei Konto-Objekten. Dies ist deshalb möglich, weil das Bank-Objekt gemäß Klassendiagramm oben in Beziehung zu den Konto-Objekten steht.

62 Übungen Aufgabe 1 (siehe www.inf-schule.de 1.12.5.6)
Erzeuge Objekte, die folgende Situation modellieren: Kunde Werner Schmidt hat das Konto mit der Nummer 23. Kundin Theresa Meier hat das Konto mit der Nummer 42. Kundin Alexandra Roth hat das Konto mit der Nummer 15. class Konto(object): def __init__(self, nummer): self.nr = nummer self.stand = 0.0 self.inhaber = None def einzahlen(self, betrag): self.stand = self.stand + betrag def auszahlen(self, betrag): self.stand = self.stand - betrag class Kunde(object): def __init__(self, name, vorname): self.name = name self.vorname = vorname

63 Übungen Aufgabe 2 (siehe www.inf-schule.de 1.12.5.6)
Ein Kunde soll neben einem Erstkonto auch ein Zweitkonto haben können. (a) Beschreibe eine typische Situation in dieser Bankwelt mit einem Objektdiagramm. (b) Beschreibe die Bankwelt auch mit einem Klassendiagramm. (c) Entwickle eine Implementierung zu dieser Bankwelt und ein Testprogramm passend zu Aufgabe (a).

64 Übungen Aufgabe 3 (siehe www.inf-schule.de 1.12.5.6)
In der freien Enzyklopädie Wikipedia werden Artikel zu Stichwörtern von Benutzern verfasst. Eine erste Modellierung der Klassen Artikel und Benutzer könnte wie folgt aussehen: (a) Implementiere die Klassen und erzeuge Objekte zur Beschreibung folgender Situation: * Der Artikel zum Stichwort HTML wurde vom Benutzer helmut03 verfasst. * Der Artikel zum Stichwort CSS wurde vom Benutzer loreley verfasst. * Der Artikel zum Stichwort Barrierefreiheit wurde vom Benutzer loreley verfasst.

65 Übungen Aufgabe 3 (siehe www.inf-schule.de 1.12.5.6)
Das Modell soll so erweitert werden, dass Artikel von Benutzern überarbeitet werden können: (b) Implementiere das erweiterte Modell und erzeuge eine typische Objektsituation. Verdeutliche die erzeugte Objektsituation auch mit einem Objektdiagramm. (c) Wie müsste man die Klasse Benutzer erweitern, wenn hier auch die Mitarbeit an Artikeln mit einem Referenzattribut erfasst werden soll.

66 Übungen Aufgabe 4 (siehe www.inf-schule.de 1.12.5.6)
Ein Geometrieprogramm soll verschiedene geometrische Objekte verwalten. Kannst du passende Klassen konzipieren und implementieren, so dass folgendes Testprogramm sinnvoll ausgeführt werden kann. from geometrie import * # Punkte p1 = Punkt(0, 0) p2 = Punkt(0, 10) p3 = Punkt(10, 10) p4 = Punkt(10, 0) p5 = Punkt(5, 15) # Rechtecke und Dreieck (als n-Eck) rechteck = Rechteck(p1, p3) dreieck = Neck([p2, p3, p5]) # Haus des Nikolaus als Figur haus_nikolaus = Figur() haus_nikolaus.hinzufuegen(rechteck) haus_nikolaus.hinzufuegen(dreieck) # Punkt verschieben und ausgeben p1.verschieben(4, 1) ...

67 Miniwelt und Datenmodell
Teil 6 Miniwelt und Datenmodell

68 Bankwelt im Computer S Konto-Nr.5 Adriana Müller Kontoauszug Blatt 3 Datum Erläuterung Betrag Handykosten Zuschuss von Oma und Opa Schuhe Kontostand in EUR, Die Bankwelt mit bestimmten Gegenständen (Kunden, Konten, ...) und Vorgängen (Ein-, Auszahlungen, ...) soll in einem Programm geeignet erfasst werden.

69 Bankwelt im Computer S Aufgabe:
Konto-Nr.5 Adriana Müller Kontoauszug Blatt 3 Datum Erläuterung Betrag Handykosten Zuschuss von Oma und Opa Schuhe Kontostand in EUR, Aufgabe: Welche Objekte sind für welche Aufgaben zuständig? Welche Vereinfachungen sind bei dieser Beschreibung einer Bankwelt vorgenommen?

70 Bankwelt im Computer from bank import * bank = Bank()
# Konten eröffnen bank.kontoEroeffnen("Müller", "Adriana", 2101) bank.kontoEroeffnen("Meier", "Adrian", 1507) bank.kontoEroeffnen("Schuster", "Christiane", 1313) bank.kontoEroeffnen("Weber", "Alexander", 2276) # Ausgabe der konten for kunde in bank.kunden: print("Kunde:") print("Name:", kunde.name) print("Vorname:", kunde.vorname) print("Kontonummer:", kunde.konto.nr) print("Kontostand:", kunde.konto.stand) print() # Transaktion print("Einzahlung") pin = int(input("PIN:")) if bank.existiertPIN(pin): meineKontoNr = bank.getKontoNr(pin) betrag = float(input("Betrag:")) bank.einzahlen(meineKontoNr, betrag) ... Aufgabe: Lade dir die Datei bank.py mit einer Implementierung der Klassen herunter. Versuche, mit den Objekten Vorgänge der Bankwelt durchzuspielen. Das folgende Python-Testprogramm zeigt, wie das gehen könnte.

71 Miniwelt Mit Miniwelt bezeichnen wir den Weltausschnitt / Gegenstandsbereich, der dem zu entwickelnden Programm (Software-System) zu Grunde liegt. S Konto-Nr.5 Adriana Müller Kontoauszug Blatt 3 Datum Erläuterung Betrag Handykosten Zuschuss von Oma und Opa Schuhe Kontostand in EUR,

72 Datenmodell Ein Modell ist eine vereinfachende Darstellung einer Miniwelt, die (für einen bestimmten Zweck ausgewählte) Teilaspekte der Miniwelt strukturgetreu beschreibt. Aufgabe eines objektorientiertes Datenmodells ist es, die Struktur der Miniwelt mit Hilfe von Objekten und deren Beziehungen zu beschreiben.

73 Zuständigkeiten Bei der Entwicklung komplexer Software-Systeme ist es günstig, dieses System aus mehreren Objekten zusammenzusetzen. Jedes Objekt sollte dabei für einen bestimmten Aufgabenbereich zuständig sein. Ein solches System aus Objekten mit klar umgrenzten Zuständigkeiten erhöht die Durchschaubarkeit des gesamten Software-Systems und erleichtert es, das System nachträglich abzuändern oder zu erweitern. Objekt der Klasse Kunde: verwaltet die Kundendaten Objekt der Klasse Konto: verwaltet die Kontodaten; führt Ein- und Auszahlungen aus Objekt der Klasse Bank: erzeugt und verwaltet alle Kunde-Objekte und Konto-Objekte; veranlasst alle Geldtransfers zwischen Konten; ...

74 UML UML steht für uniform modeling language und ist eine normierte Bildsprache, mit der man objektorientierte Modelle beschreiben kann. Objektdiagramm Klassendiagramm Sequenzdiagramm

75 UML-Editor Violet ist ein sehr einfaches, frei nutzbares Werkzeug zur Erstellung von UML-Diagrammen. siehe:

76 Übungen Aufgabe 1 (siehe www.inf-schule.de 1.12.6.6)
Beim chuck-a-luck-Spiel soll ein Objekt der Klasse Spiel alle beteiligten Objekte verwalten und die Spielaktionen als Operationen zur Verfügung stellen. (a) Skizziere ein Objektdiagramm zur Miniwelt chuck-a-luck. (b) Woran erkennt man im Klassendiagramm, dass das Spiel-Objekt für die Erzeugung der weiteren Objekte zuständig ist? Welche weiteren Zuständigkeiten hat das Spiel-Objekt? (c) Implementiere dieses Modell. Teste es wie folgt. from chuckaluck import * # Erzeugung der Objekte spiel = Spiel() # Durchführung eines Spiels spiel.einsatzZahlen() spiel.spielzahlSetzen(5) spiel.wuerfelWerfen() spiel.gewinnAuszahlen() # Ausgabe der Spiel print("Würfel A:", spiel.wuerfelA.augen) ...

77 Übungen Aufgabe 2 (siehe www.inf-schule.de 1.12.6.6)
Das folgende Klassendiagramm zeigt ein System, mit dem man die Entwicklung einer Population simulieren kann. (a) Implementiere die Klasse Population so, dass die Mäusepopulation aus ... (siehe Einstieg - Mäusepopulation) als Miniwelt erfasst wird. (b) Implementiere die Klasse Simulator so, dass sie die Entwicklung der verwalteten Population beschreibt. (c) Erstell ein geeignetes Testprogramm, um die Implementierung zu überprüfen.. (d) Was müsste am Datenmodell verändert werden, wenn man die Population aus ... (siehe Miniprojekt) modellieren wollte?

78 Übungen Aufgabe 3 (siehe www.inf-schule.de 1.12.6.6)
Ein Zahlenschloss bestehe aus drei Einstellrädern, mit denen die Ziffern der Schlüsselzahl einzeln eingestellt werden können. Hat man die Schlüsselzahl richtig getroffen, dann ist das Schloss offen. Entwickle ein objektorientiertes Datenmodell, das die vorliegende Miniwelt möglichst strukturgetreu beschreibt. Stell das Datenmodell auch mit Hilfe von UML-Diagrammen dar. Implementiere und teste das Datenmodell.

79 Datenmodell und grafische Benutzeroberfläche
Teil 7 Datenmodell und grafische Benutzeroberfläche

80 Eine GUI zur Bankwelt Das bisher entwickelte Programm zur Verwaltung von Bankkonten soll um eine grafische Benutzeroberfläche erweitert werden. Der Benutzer soll die Möglichkeit haben, wie an einem Terminal in der Bank seine Bankgeschäfte zu erledigen. Am Terminal kann man sich den aktuellen Kontostand anzeigen lassen, Geldbeträge ein- und auszahlen und auch Überweisungen vorzunehmen.

81 Eine GUI zur Bankwelt # # Datenmodell from bank import * bank = Bank() bank.initBank() # GUI from tkinter import * # ... Prozeduren zur Ereignisverarbeitung # Erzeugung des Fensters fenster = Tk() fenster.title("Bank") fenster.geometry('230x330') ... Aufgabe: Das gezeigte Programm (siehe ...) enthält zwar noch Implementierungslücken, ist aber nichtsdestotrotz lauffähig. Teste zunächst das Programm. Mache dich auch mit dem Quelltext vertaut. Analysiere insbesondere die schon implementierten Ereignisverarbeitungsprozeduren. Implementiere die noch fehlenden Implementierungen.

82 Eine GUI zur Bankwelt from tkinter import * class GUIBank(object):
def __init__(self, bank): # Referenzattribute zum Datenmodell self.bank = bank # Erzeugung des Fensters self.fenster = Tk() self.fenster.title("Bank") self.fenster.geometry('230x330') # Rahmen PIN self.rahmenPIN = Frame(master=self.fenster, background="#FFCFC9") self.rahmenPIN.place(x=5, y=5, width=220, height=30) # Label mit Aufschrift PIN self.labelPIN = Label(master=self.rahmenPIN, background="white", text="PIN") self.labelPIN.place(x=5, y=5, width=145, height=20) # Entry für die PIN self.entryPIN = Entry(master=self.rahmenPIN) self.entryPIN.place(x=155, y=5, width=60, height=20) ... def Button_Anzeigen_Click(self): pin = int(self.entryPIN.get()) Aufgabe: Der folgende Quelltextauszug zeigt eine andere Implementierung der grafischen Benutzeroberfläche. Hier wird ein zusätzliches Objekt benutzt, um sämtliche GUI-Objekte zu verwalten. Analysiere das Programm.

83 Eine GUI zur Bankwelt # # Datenmodellobjekte from bank import * bank = Bank() bank.initBank() # GUI-Objekte from guibank import * guibank = GUIBank(bank) Aufgabe: Welche Beziehungen bestehen zwischen den Objekten? Verdeutliche dies mit einem Objekt- und Klassendiagramm.

84 Zwei-Komponenten-Architektur
Das bisher entwickelte System zur Verwaltung von Bankkonten hat eine Zwei-Komponenten-Architektur. Die eine Komponente wird vom Datenmodell gebildet. Diese Komponente ist so konzipiert, dass sie ohne eine grafische Benutzeroberfläche benutzt werden kann. Die andere Komponente umfasst alle Klassen, die für die Erzeugung und Verwaltung der grafischen Benutzeroberfläche benötigt werden. Da Objekte dieser Klassen u. a. für die Darstellung des Datenmodells zuständig sind, dürfen sie Zugriff auf Datenmodell-Objekte haben. # # Datenmodellobjekte from bank import * bank = Bank() bank.initBank() # GUI-Objekte from guibank import * guibank = GUIBank(bank)

85 Trennung Datenmodell - GUI
Die Trennung zwischen Datenmodell und GUI ist ein Prinzip bei der Entwicklung von Systemen mit grafischer Benutzeroberfläche, das hilft, klar strukturierte und gut wartbare Programme zu erstellen: Während GUI-Objekte auf Objekte des Datenmodells zugreifen dürfen, ist der umgekehrte Zugriff nicht erlaubt.

86 Model - View - Control Bisher war das GUI-Objekt sowohl für die Präsentation der Daten auf der Benutzerober-fläche, als auch für die Ereignisverarbeitung zuständig. Diese beiden Zuständigkeiten sollen jetzt aufgeteilt werden: Einerseits soll es Präsentations-objekte geben, die nur für die Darstellung der Daten zuständig sind, andererseits Steuerungs-objekte, die die Verbindungen zwischen Präsentationsobjekten und Datenmodellobjekten herstellen und die Ereignisverarbeitung festlegen. Diese weitere Aufteilung der Zuständigkeiten soll spätere Änderungen oder Erweiterungen des Softwaresystems erleichtern und eine Wiederverwendbarkeit einzelnen Komponenten ermöglichen. View Control Model

87 Model - View - Control class Konto(object):
def __init__(self, nummer): self.nr = nummer self.stand = 0.0 self.inhaber = None ... class Kunde(object): def __init__(self, name, vorname, pin): self.name = name self.vorname = vorname self.pin = pin self.konto= None class Bank(object): def __init__(self): self.konten = [] self.kunden = [] self.naechsteKontoNr = 0 Model

88 Model - View - Control from tkinter import * View
class GUIBank(object): def __init__(self, bank, \ cbAnzeigen, cbEinzahlen, cbAuszahlen, cbUeberweisen): # Referenzattribute zum Datenmodell self.bank = bank self.cbAnzeigen = cbAnzeigen self.cbEinzahlen = cbEinzahlen self.cbAuszahlen = cbAuszahlen self.cbUeberweisen = cbUeberweisen # Erzeugung des Fensters self.fenster = Tk() self.fenster.title("Bank") self.fenster.geometry('230x330') # Button Anzeigen self.buttonAnzeigen = Button(master=self.rahmenKonto, text="anzeigen", \ command=self.cbAnzeigen) self.buttonAnzeigen.place(x=5, y=55, width=145, height=20) ... # kein mainloop hier View

89 Model - View - Control from model_bank import *
from view_bank import * class Controler(object): def __init__(self): # Erzeugung der Datenmodell-Objekte self.bank = Bank() self.bank.initBank() # Erzeugung und Initialisierung der GUI self.guibank = GUIBank(self.bank, self.buttonAnzeigen, self.buttonEinzahlen, ...) # Ereignisschreife self.guibank.fenster.mainloop() def buttonAnzeigen(self): pin = int(self.guibank.entryPIN.get()) if self.bank.existiertPIN(pin): kunde = self.bank.getKunde(pin) self.guibank.labelKontonummer.config(text=str(kunde.konto.nr)) self.guibank.labelKontostand.config(text=str(kunde.konto.stand)) else: self.guibank.labelKontonummer.config(text="") self.guibank.labelKontostand.config(text="") ... controler = Controler() Control

90 Model - View - Control Aufgabe eines GUIBank-Objekts ist es, die grafische Benutzeroberfläche zu erzeugen. View Control Model Aufgabe eines Model-Objekts ist es, einen Aspekt der Miniwelt abzubilden.. Aufgabe eines Controler-Objekts ist es, die Datenmodell- und GUI-Objekte zu erzeugen und zu verknüpfen. Beachte, dass ein Controler-Objekt Zugriff auf Model- und View-Objekte hat.

91 Parameter für eine Callback-Funktion
Eine Callback-Funktion (bzw. Rückruffunktion) ist eine Funktion, die einer anderen Funktion als Parameter übergeben wird und von dieser unter gewissen Bedingungen aufgerufen wird. class GUIBank(object): def __init__(self, bank, cbAnzeigen, cbEinzahlen, cbAuszahlen, cbUeberweisen): # Referenzattribute zum Datenmodell self.bank = bank self.cbAnzeigen = cbAnzeigen self.cbEinzahlen = cbEinzahlen self.cbAuszahlen = cbAuszahlen self.cbUeberweisen = cbUeberweisen # Erzeugung des Fensters self.fenster = Tk() self.fenster.title("Bank") self.fenster.geometry('230x330') # Button Anzeigen self.buttonAnzeigen = Button(master=self.rahmenKonto, text="anzeigen", \ command=self.cbAnzeigen) self.buttonAnzeigen.place(x=5, y=55, width=145, height=20) ... Parameter für eine Callback-Funktion

92 Callback-Funktion Eine Callback-Funktion (bzw. Rückruffunktion) ist eine Funktion, die einer anderen Funktion als Parameter übergeben wird und von dieser unter gewissen Bedingungen aufgerufen wird. class Controler(object): def __init__(self): # Erzeugung der Datenmodell-Objekte self.bank = Bank() self.bank.initBank() # Erzeugung und Initialisierung der GUI self.guibank = GUIBank(self.bank, self.buttonAnzeigen, self.buttonEinzahlen, ...) # Ereignisschreife self.guibank.fenster.mainloop() def buttonAnzeigen(self): pin = int(self.guibank.entryPIN.get()) if self.bank.existiertPIN(pin): kunde = self.bank.getKunde(pin) self.guibank.labelKontonummer.config(text=str(kunde.konto.nr)) self.guibank.labelKontostand.config(text=str(kunde.konto.stand)) else: ... Callback-Funktion Callback-Funktion

93 Strategie: Befragen Das Objekt guiuhr nutzt eine Strategie, die man Befragen oder Polling nennt. Das Objekt guiuhr weiß genau, wann sich das Datenmodell ändert (nach jedem Anklicken der Schaltfläche) und besorgt sich die geänderten Daten zur Anzeige auf dem vorgesehenen Label. class Uhr(object): ... def tick(self): if self.sekunden < 59: self.sekunden = self.sekunden + 1 else: self.sekunden = 0 if self.minuten < 59: self.minuten = self.minuten + 1 from tkinter import * class GUIUhr(object): def __init__(self, uhr): # Referenzattribute zum Datenmodell self.uhr = uhr # Erzeugung des Fensters # Button self.buttonTick = Button(..., command=self.Button_Tick_Click) ... def Button_Tick_Click(self): # Verarbeitung der Daten self.uhr.tick() # Anzeige der Daten uhrzeit = str(self.uhr.stunden) + ":" + \ str(self.uhr.minuten) + ":" + \ str(self.uhr.sekunden) self.labelUhr.config(text=uhrzeit) Änderung # Datenmodell from uhr import * uhr = Uhr() # GUI-Objekt from guiuhr import * guiuhr = GUIUhr(uhr) guiuhr.fenster.mainloop() Befragen

94 Strategie: Beobachten
Das Objekt guiuhr nutzt hier eine Strategie, die man Beobachten nennt. Das Objekt guiuhr wird als registriertes beobachtendes Objekt jeweils benachrichtigt, wenn sich das Datenmodell verändert hat. import threading, time class Timer(threading.Thread): ... class Uhr(object): def __init__(self): self.aktiv = False self.beobachter = None def setBeobachter(self, beobachter): self.beobachter = beobachter def stellen(self, h, m, s): self.stunden.setzen(h) self.minuten.setzen(m) self.sekunden.setzen(s) self.beobachter.anzeigeAktualisieren() ... def stoppen(self): self.aktiv = False def tick(self): if self.sekunden < 59: self.sekunden = self.sekunden + 1 else: self.sekunden = 0 self.beobachter.anzeigeAktualisieren() if self.aktiv: self.timer = Timer(1, self.tick) self.timer.start() def ticken(self): self.aktiv = True Änderung Beobachter benachrichtigen

95 Strategie: Beobachten
Beachte, dass die Klassen Uhr und GUIUhr so gestaltet sind, dass die Trennung zwischen Datenmodell und GUI weiterhin Bestand hat. Erst zur Laufzeit wird der Beobachter des Datenmodellobjekts festgelegt. from tkinter import * class GUIUhr(object): def __init__(self, uhr): # Referenzattribute zum Datenmodell self.uhr = uhr ... def Button_Start_Click(self): # Verarbeitung der Daten self.uhr.ticken() def Button_Stopp_Click(self): self.uhr.stoppen() def anzeigeAktualisieren(self): # Anzeige der Daten uhrzeit = str(self.uhr.stunden)+":"+ str(self.uhr.minuten)+":" +str(self.uhr.sekunden) self.labelUhr.config(text=uhrzeit) # Datenmodell from uhr import * uhr = Uhr() # GUI-Objekt from guiuhr import * guiuhr = GUIUhr(uhr) # Beobachter festlegen uhr.setBeobachter(guiuhr) # Ereignisschleife starten guiuhr.fenster.mainloop()

96 Übungen Aufgabe 1 (siehe www.inf-schule.de 1.12.7.8)
Die Klasse ModuloZaehler beschreibe Zähler, die modulo einer vorgegebenen Zahl zählen. Entwickle eine einfache grafische Benutzeroberfläche, mit der man das Verhalten eines Modulo-Zählers verdeutlichen kann.

97 Übungen Aufgabe 2 (siehe www.inf-schule.de 1.12.7.8)
Ziel ist es, ein objektorientieres Datenmodell mit einer grafische Benutzeroberfläche zu verknüpfen. Als Miniwelt betrachten wir das Spiel chuck a luck.

98 Übungen Aufgabe 2 (siehe www.inf-schule.de 1.12.7.8)
Für die Benutzeroberfläche kannst du eine bereits entwickelte Implementierung übernehmen. Implementiere das gesamte Programm so, dass eine klare Trennung zwischen Datenmodell und GUI erkennbar ist.

99 Teil 6 Vererbung

100 Sparkonto Ein Sparkonto ist ein Konto, bei dem das eingezahlte Geld mit einem bestimmten, mit der Bank vereinbarten Zinssatz verzinst wird. Das folgende Klassendiagramm zeigt ein Sparkonto im Vergleich zu einem normalen Konto. Aufgabe: Vergleiche die Klassendiagramme. Inwiefern unterscheiden sich die Attribute und Methoden der beiden Klassen? Überleg dir auch, ob sich bestimmte Methoden evtl. anders verhalten. Beachte, dass man das den Klassendiagrammen nicht entnehmen kann. Hinweis: Welche Regelungen gibt es bei Auszahlungen von einem Sparkonto?

101 Sparkonto Ein Sparkonto kann als spezielles Konto angesehen werden, das - im Vergleich zu einem herkömmlichen Konto - nur in einigen Bestandteilen abgeändert worden ist. Aufgabe: Wie würde man ein solches Klassendiagramm wohl lesen?

102 Sparkonto class Konto(object): def __init__(self, nummer):
self.nr = nummer self.stand = 0 self.minimum = def einzahlen(self, betrag): self.stand = self.stand + betrag def auszahlen(self, betrag): if self.stand - betrag >= self.minimum: self.stand = self.stand - betrag else: print("Auszahlung nicht möglich!") class Sparkonto(Konto): def __init__(self, nummer): Konto.__init__(self, nummer) self.zinssatz = None self.minimum = 0 self.maxAuszahlung = def setZinssatz(self, zinssatz): self.zinssatz = zinssatz def auszahlen(self, betrag): if betrag <= self.maxAuszahlung: if self.stand - betrag >= self.minimum: self.stand = self.stand - betrag else: print("Auszahlung nicht möglich!") def zinsenGutschreiben(self): zinsen = self.stand * (self.zinssatz / 100) self.einzahlen(zinsen) Aufgabe: Analysiere die Implementierung der Klasse Sparkonto. Alles klar? Teste auch diese Implementierung.

103 Basisklasse / Superklasse
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 Basisklasse oder Superklasse. Basisklasse / Superklasse Subklasse Ü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.

104 Implementierung in Python
Vererbung class Konto(object): def __init__(self, nummer): self.nr = nummer self.stand = 0 self.minimum = def einzahlen(self, betrag): self.stand = self.stand + betrag def auszahlen(self, betrag): if self.stand - betrag >= self.minimum: self.stand = self.stand - betrag else: print("Auszahlung nicht möglich!") class Sparkonto(Konto): def __init__(self, nummer): Konto.__init__(self, nummer) self.zinssatz = None self.minimum = 0 self.maxAuszahlung = def setZinssatz(self, zinssatz): self.zinssatz = zinssatz def auszahlen(self, betrag): if betrag <= self.maxAuszahlung: if self.stand - betrag >= self.minimum: self.stand = self.stand - betrag else: print("Auszahlung nicht möglich!") def zinsenGutschreiben(self): zinsen = self.stand * (self.zinssatz / 100) self.einzahlen(zinsen) Ergänzen Übernehmen Überschreiben

105 Übungen Aufgabe (siehe www.inf-schule.de 1.12.7.1 und 1.12.8.5)
Auf den folgenden Folien werden verschiedene Implementierungen einer grafischen Benutzeroberfläche gezeigt. Analysiere und erkläre, was in den jeweiligen Version unterschiedlich implementiert wird.

106 Übungen # Datenmodell from wuerfel import * from random import randint
wuerfel = Wuerfel() # GUI from tkinter import * # Ereignisverarbeitung def Wuerfel_Click(): # Verarbeitung der Daten wuerfel.werfen() # Anzeige der Daten labelWuerfel.config(text=str(wuerfel.augen)) # Erzeugung des Fensters fenster = Tk() fenster.title("Würfel") fenster.geometry('120x110') # Eingabefeld für die Zahl labelWuerfel = Label(master=fenster, text="1", background="#FBD975") labelWuerfel.place(x=45, y=40, width=30, height=30) # Button zum Auswerten buttonWuerfel = Button(master=fenster, text="Würfel werfen", command=Wuerfel_Click) buttonWuerfel.place(x=10, y=80, width=100, height=20) # Aktivierung des Fensters fenster.mainloop() from random import randint class Wuerfel(object): def __init__(self): self.augen = 1 def werfen(self): self.augen = randint(1, 6)

107 Übungen from tkinter import * # Datenmodell class GUIWuerfel(object):
def __init__(self, wuerfel): # Referenzattribute zum Datenmodell self.wuerfel = wuerfel # Erzeugung des Fensters self.fenster = Tk() self.fenster.title("Bank") self.fenster.geometry('120x110') # Eingabefeld für die Zahl self.labelWuerfel = Label(master=self.fenster, text="1", background="#FBD975") self.labelWuerfel.place(x=45, y=40, width=30, height=30) # Button zum Auswerten self.buttonWuerfel = Button(master=self.fenster, text="Würfel werfen", command=self. Wuerfel_Click) self.buttonWuerfel.place(x=10, y=80, width=100, height=20) def Wuerfel_Click(self): # Verarbeitung der Daten self.wuerfel.werfen() # Anzeige der Daten self.labelWuerfel.config(text=str(self.wuerfel.augen)) # Datenmodell from wuerfel import * wuerfel = Wuerfel() # GUI-Objekt from guiwuerfel import * guiwuerfel = GUIWuerfel(wuerfel) guiwuerfel.fenster.mainloop()

108 Übungen from tkinter import * # Datenmodell class GUIWuerfel(Tk):
def __init__(self, wuerfel): # Referenzattribute zum Datenmodell Tk.__init__(self) self.wuerfel = wuerfel # Erzeugung des Fensters self.title("Würfel") self.geometry('120x110') # Eingabefeld für die Zahl self.labelWuerfel = Label(master=self, text="1", background="#FBD975") self.labelWuerfel.place(x=45, y=40, width=30, height=30) # Button zum Auswerten self.buttonWuerfel = Button(master=self, text="Würfel werfen", command=self.Button_Wuerfel_Click) self.buttonWuerfel.place(x=10, y=80, width=100, height=20) def Button_Wuerfel_Click(self): # Verarbeitung der Daten self.wuerfel.werfen() # Anzeige der Daten self.labelWuerfel.config(text=str(self.wuerfel.augen)) # Datenmodell from wuerfel import * wuerfel = Wuerfel() # GUI-Objekt from guiwuerfel import * guiwuerfel = GUIWuerfel(wuerfel) guiwuerfel.mainloop()

109 Literaturhinweise Es gibt eine Vielzahl von fachwissenschaftlichen Darstellungen zur objektorientierten Modellierung und Programmierung. Hier wurden folgende Lehrwerke benutzt: - D. J. Barnes, M. Kölling: Objektorientierte Programmierung mit Java. Pearson - Studium Helmut Balzert: Lehrbuch Grundlagen der Informatik. Spektrum Ak. Verlag Bernd Oestereich: Objektorientierte Softwareentwicklung. Oldenbourg 1998. Dagegen gibt es nur wenige Schulbücher, die systematisch in die objektorientierte Programmierung einführen, z. B.: - Siegfried Spolwig: Objektorientierung im Informatikunterricht. Dümmler-Verlag P. Damann, J. Wemßen: Objektorientierte Programmierung mit Delphi, Band 2. Klett-Verlag 2003. Viele interessante Artikel mit Unterrichtsvorschlägen bzw. fachdidaktischen Auseinandersetzungen findet man in der Zeitschrift LOG IN. Das Themenheft 128/129 ist speziell dem Thema „Objektorientiertes Modellieren und Programmieren“ gewidmet. ...

110 Literaturhinweise Im Internet findet man ebenfalls sehr viele schulgerechte Darstellungen der objektorientierten Modellierung und Programmierung, z. B: Die AG-Informatik des LMZ in RLP stellt u. a. auch Fortbildungsmaterialien zu diesem Thema bereit. Auf der Homepage des HSG in Kaiserslautern findet man Unterrichtsmaterialien und Links zu weiteren interessanten Seiten. ... Die Darstellung hier orientiert sich an den Materialien auf den Webseiten:


Herunterladen ppt "Konzepte objektorientierter Programmierung"

Ähnliche Präsentationen


Google-Anzeigen