Objektorientierte Modellierung & Programmierung (OOPM)
IN-SA TB #001–013
Einführung
Seit Beginn der 90er Jahre hat sich die OOP (Objektorientierte Programmierung) in der Praxis mehr und mehr durchgesetzt.
Vorteile
- Wiederverwendbarkeit von schon programmierten Einheiten
- Aufteilung in überschaubare Einzelteile
- Erweiterung durch Schnittstellen
Das objektorientierte Paradigma teilt sich in zwei miteinander verzahnte Bereiche auf:
| Bereich | Bedeutung |
|---|---|
| OOM | Objektorientierte Modellierung |
| OOP | Objektorientierte Programmierung |
Alan Kay: „Alles ist ein Objekt"
Die Grundidee der OOP und OOM ist, Daten und sogenannte Methoden, die auf diese Daten arbeiten, in einem sogenannten Objekt zusammenzufassen.
Wichtige Begriffe
| Begriff | Definition |
|---|---|
| Klasse | Bauplan für Objekte. Darin werden die grundlegenden Gemeinsamkeiten der einzelnen Objekte festgelegt. |
| Objekt (auch Instanz) | Ein konkretes Exemplar einer Klasse mit eindeutigem Objektnamen und ganz bestimmten festgelegten Eigenschaften (Attributwerten). |
| Attribut | Eigenschaften eines Objekts. |
| Methode | Fähigkeiten eines Objektes (Algorithmen). |
UML – Unified Modelling Language
„Sprache" unter anderem zur Veranschaulichung von Klassen und Beziehungen zwischen ihren Objekten.
Aufbau einer Klassenkarte (UML-Klassendiagramm)
┌─────────────────────┐
│ Klassenname │ ← Name der Klasse
├─────────────────────┤
│ - attribut1 : Typ │ ← Attribute (privat = -)
│ - attribut2 : Typ │
├─────────────────────┤
│ + methode1() │ ← Methoden (öffentlich = +)
│ + methode2() │
└─────────────────────┘
Zugriffsmodifikatoren (Sichtbarkeit)
| Symbol | Sichtbarkeit | Bedeutung |
|---|---|---|
- | private | Nur innerhalb der Klasse sichtbar |
+ | public | Von überall sichtbar |
# | protected | Für Unterklassen sichtbar |
Das Geheimnisprinzip (Datenkapselung)
Nur Methoden sollen Attributwerte ändern!
- Alle Attribute sind privat (
-) - Methoden sind in der Regel öffentlich / public (
+)
Beispiel: Klasse Auto
UML-Klassendiagramm
┌────────────────────────┐
│ Auto │
├────────────────────────┤
│ - geschwindigkeit: int │
│ - farbe: string │
│ - tankfüllung: int │
├────────────────────────┤
│ + gasgeben() │
│ + bremsen() │
│ + tanken(menge: int) │
└────────────────────────┘
Übersetzung in Python
class Auto:
# Konstruktor
def __init__(self, farbe):
self.__geschwindigkeit = 0
self.__farbe = farbe
self.__tankfüllung = 20
def gasgeben(self):
# Algorithmus
if self.__tankfüllung > 0:
self.__geschwindigkeit += 1
self.__tankfüllung -= 1
else:
print("Tanken!")
def bremsen(self):
if self.__geschwindigkeit > 0:
self.__geschwindigkeit -= 1
else:
print("Fahrzeug steht!")
def tanken(self, menge):
self.__tankfüllung += menge
# Objekte erzeugen
auto1 = Auto("rot")
auto1.tanken(40)
for i in range(65):
auto1.gasgeben()
Der Klassenkonstruktor
Zur Erzeugung eines Objektes wird der sogenannte Konstruktor aufgerufen – eine spezielle Methode, mit der Attribute initialisiert werden (d.h. die Startwerte können festgelegt werden).
Man sagt: Ein Objekt wird durch den Aufruf des Konstruktors erzeugt und initialisiert.
Konstruktor in Python
def __init__(self, parameterliste):
self.__attributname = wert # Attribute
Aufruf des Konstruktors
objektbezeichner = Klassenname(Parameterwerte)
Beispiel: Klasse Sim
class Sim:
def __init__(self, name):
self.__alter = 17
self.__name = name
sim1 = Sim("Bob")
Punktnotation
Nachdem ein Objekt erzeugt wurde, können seine Attribute durch das Aufrufen seiner Methoden geändert werden. Auf die Methoden eines Objekts kann durch Verwendung der Punktnotation zugegriffen werden:
objektname.methodenname()
sim1.trinken()
Standardmethoden: Getter und Setter
Wegen des Geheimnisprinzips können und sollen Attribute nur durch Methoden verändert werden. Innerhalb der Methoden können Bedingungen formuliert werden, die die Daten im Sinne des Programmierers schützen.
def getAlter(self):
return self.__alter # gibt den Wert von Alter zurück
def setAlter(self, alter):
self.__alter = alter # setzt den Wert von Alter
def getName(self):
return self.__name
def setName(self, name):
self.__name = name
Klassendiagramm & Assoziationen
Klassen können in Beziehungen zueinander gestellt werden. Beziehungen zwischen Objekten von Klassen nennt man Assoziationen.
Aggregation
Um ein Objekt in Beziehung zu seinen Bestandteilen zu sehen, verwendet man Assoziationen – sog. Aggregation.
In UML: Klasse1 ◇──── Klasse2
Das heißt: Ein Objekt der Klasse1 enthält/besitzt ein Objekt der Klasse2.
Beispiel: Sim besitzt ein Bett
class Sim:
def __init__(self):
self.__bett = None
def bettkaufen(self, bett):
self.__bett = bett
def schlafen(self):
self.__bett.setGemacht(False)
Bekanntschaft zwischen Klassen
Eine Beziehung zwischen zwei Klassen liegt vor, wenn:
- Klasse1 mindestens eine Methode mit einem Übergabeparameter vom Typ
Klasse2definiert, oder - Klasse2 mindestens ein Attribut vom Typ
Klasse1besitzt.
Methoden mit Rückgabe (Getter)
Methoden mit Rückgabe besitzen als letzte Anweisung im Methodenrumpf ein return-Statement.
In UML
methode1(u: int) : int
In Python
def methode1(self, u):
# Algorithmus
return ... # int
Ruft man eine Methode auf, die eine Rückgabe generiert, kann man diesen Wert an der Stelle des Aufrufs erwarten:
antwort = objekt.methoden(1, 2)
# Methode wird aufgeführt, Rückgabe wird generiert
Lokale vs. Globale Variablen
| Typ | Gültigkeit | Beispiel |
|---|---|---|
| Lokale Variable | Nur innerhalb der Methode, in der sie definiert wird | y = 5 in einer Methode |
| Globale Variable | Für alle Methoden (= Attribute) | x = 5 auf Klassenebene |
x = 5 # global
def methode(self):
y = 5 # lokal
Datentypen
Primitive Datentypen
| Typ | Beschreibung |
|---|---|
int | Ganzzahl |
string | Zeichenkette |
float | Gleitkommazahl |
bool | Wahrheitswert (True / False) |
Zusammengesetzte Datentypen (Klassen)
Ein Attribut kann selbst den Typ einer Klasse haben:
Mensch:
- gebDat: Datum
Datum:
- tag: int
- monat: int
- jahr: int
Vererbung
Konzept
Eine Vererbungsbeziehung (auch: Generalisierung / Spezialisierung) liegt vor, wenn eine Klasse alle Attribute und Methoden einer anderen Klasse erbt. Die erbende Klasse heißt Unterklasse, die vererbende Klasse heißt Oberklasse (auch: Superklasse).
Ziel: Vermeidung von doppeltem Code.
Die Unterklassen erben dabei alle Attribute und Methoden der Oberklasse. Methoden können überschrieben werden, falls sie unpassend sind – das nennt man Polymorphie.
Sichtbarkeit bei Vererbung
Attribute, die für Unterklassen zugänglich sein sollen, müssen protected (#) statt private (-) sein.
In UML
Charakter
/ | \
Elf Troll Zwerg
Offener Pfeil von Unterklasse zur Oberklasse.
Beispiel-Klassendiagramm
┌──────────────────────┐
│ Charakter │
├──────────────────────┤
│ * name: str │
│ # lebenspunkte: int │
├──────────────────────┤
│ + angreifen() │
└──────────┬───────────┘
│
┌──────┴──────┬──────────┐
▼ ▼ ▼
┌────────┐ ┌─────────┐ ┌────────┐
│ Elf │ │ Troll │ │ Zwerg │
├────────┤ ├─────────┤ ├────────┤
│-gold: │ │-steine: │ │-erz: │
│ int │ │ int │ │ int │
├────────┤ ├─────────┤ ├────────┤
│+singen │ │+angreif.│ │+erzabb.│
└────────┘ └─────────┘ └────────┘
Vererbung in Python
class Charakter:
def __init__(self, name, lebenspunkte):
self._name = name # protected (1 Unterstrich)
self._lebenspunkte = lebenspunkte
def angreifen(self):
print("wusch")
class Elf(Charakter): # Elf erbt von Charakter
def __init__(self, name, lebenspunkte, gold):
super().__init__(name, lebenspunkte) # Konstruktor der Oberklasse aufrufen!
self.__gold = gold
def singen(self):
print("lalala")
# Objekte erzeugen
frie = Elf("Frie", 100000, 1700)
frie.singen() # lalala
frie.angreifen() # wusch (geerbt!)
Wichtig: Im Konstruktor der Unterklasse muss als erste Anweisung immer
super().__init__(parameterliste)stehen, um den Konstruktor der Oberklasse aufzurufen!
Vollständige UML-Notation (Übersicht)
┌──────────────────────────────────────┐
│ Klassenname │
├──────────────────────────────────────┤
│ Zugriffsmod Attributname : Datentyp │
├──────────────────────────────────────┤
│ Zugriffsmod Methodenname( │
│ Eingabeparam : Typ) │
│ : Rückgabetyp│
└──────────────────────────────────────┘
| Zugriffsmodifikator | Symbol |
|---|---|
| public | + |
| private | - |
| protected | # |