UML Diagramm in Python umsetzen?
Chrutschow. Nachdem mein Versuch, vorgegebene Datentypen in ein Klassendiagramm zu schreiben, bemerkenswert kläglich scheiterte, heute nun the-other-way-round: Ein UML Diagramm in Python umsetzen:
Insbesondere frage ich mich, wie bei der Implementierung zwischen Vererbung, Aggregation und gerichteten Assoziationen unterschieden wird. Scheinbar gibt es dafür 2000 Tutorials mit 30000 unterschiedlichen Lösungsansätzen. Außerdem weiß ich nicht, was genau die einzelnen Objekte tun. Zum Beispiel steht beim Professor nur Kostencenternummer als geschützte Variable. Und der WiMi macht anscheinend gar nichts. Was schreibe ich in die Getter und Setter?
Hier der bisherige Ansatz:
######Vererbung
"""This programm models the UML diagram of the inheritante between
members and professors.
"""
class Member:
name = ""
def __init__(self, name, id_number):
self.name = name
self.id_number = id_numer
class Professor(Member):
def __init__(self, name, id_number, cost_center_no):
self.name = name
self._cost_center_no = _cost_center_no
def get_cost_center_no(self):
# Wie Kostenstellennummer umsetzen?
class WiMi(Member):
def __init__(self, name, id_number):
self.name = name
Aggregation
class Presentation:
def __init__ (self, title, date):
self.title = name
self.date = date
def change_date(self):
print ("Class Owner: method1")
Gerichtete Assoziation
class research_group:
def __init__(self, name, total_presentation):
self.name = name
self.total_presentation = total_presentation
self.name = name
def get_members(id_number, name, total_representation):
def get_head (id_number, name, total_reprensentation)
def set_head (id_number, name, total_reprensentation)
def add_member (id_number, name, total_representation)
#Was machen diese Methoden?
1 Antwort
Insbesondere frage ich mich, wie bei der Implementierung zwischen Vererbung, Aggregation und gerichteten Assoziationen unterschieden wird.
Gegeben sei dieses Programm:
class Company:
def __init__(self):
self.officeEmployees = []
class Employee:
# a class describing an employee
class OfficeEmployee(Employee):
# a class describing an office employee
Die Klasse OfficeEmployee erbt von Employee (Generalization), denn dieser spezifiziert den Typ des Emplyoee (is-a-relation).
Die Company hat eine Liste von Büroangestellten (Aggregation). Angestellter und Firma können jeweils unabhängig voneinander existieren, stehen aber in Abhängigkeit zueinander (has-a-relation). Würdest du hingegen den Motor eines Autos via Assoziation darstellen wollen, würde man eher von einer Komposition reden.
Lies dazu auch hier: https://www.visual-paradigm.com/guide/uml-unified-modeling-language/uml-aggregation-vs-composition/
Zum Beispiel steht beim Professor nur Kostencenternummer als geschützte Variable.
Daher wird sie ihm zugeordnet.
Und der WiMi macht anscheinend gar nichts (...)
Exakt.
Was schreibe ich in die Getter und Setter?
Na, was sollen die Methoden wohl tun?
Ein Beispiel:
class Fruit:
def get_color(self):
return self.color
def set_color(self, color):
self.color = color
# ...
Zu deinem Ansatz:
Eigentlich müsste die Klasse Member abstrakt sein. Dies kann man in Python via abc-Modul realisieren. Die Signatur des Konstruktors ist falsch - im UML-Diagramm wurde kein solche definiert. Also belasse es beim Standardkonstruktor, z.B. so:
class Member:
def __init__(self):
self.name = ""
self.id_number = None
Dies gilt folgend auch für all deine anderen Klassen.
Die Methode change_date sollte an sich das tun, was ihr Name aussagt. Eine Ausgabe auf der Konsole sehe ich dabei nicht. So wie es aussieht, wurden im gesamten Programm nie Parameter für die Funktionen definiert, was ich nicht sinnig finde. Eine logische Implementation wäre von daher eher diese:
def change_date(self, date):
self.date = date
Bei deiner ResearchGroup (du hast übrigens ihren Namen falsch geschrieben) hast du das Attribut name doppelt definiert. Eine oder mehrere Instanzen der Klasse können n Members haben. Daher wäre ein Attribut members sinnvoll, was die Methoden get_,member und add_member machen sollen, sollte sich daraus erschließen. Das Gleiche gilt für ein Attribut head. Eine/Mehrere Forschungsgruppe/n können jeweils einen Anführer haben.
Huch, stimmt, da ist ja noch was.
Im UML steht ja, dass ein Member n Presentations haben kann (Aggregation). Dies lässt sich ziemlich einfach in dieser Zuweisung ausdrücken:
self.presentations = [] # in Member
Nun hat der Member eine Liste, in der alle Präsentationen gespeichert werden können. Wäre es andersherum, würde es so aussehen:
self.members = [] # in Presentation
In dem Fall gar nicht. Würdest du eine Buchstabeneingabe bei erwarteter Zahl abfedern wollen, wäre so etwas wie try-expect verständlich, da es ein Fehlerfall wäre, der einkalkulierbar ist. Wenn jedoch versucht wird, die Struktur eines Objekts aufzubiegen, ist es schlichtweg ein Fehler.
Ich weiß zwar nicht, wie du das 4. Argument über den Konstruktor entgegennimmst, doch wenn es nur 3 Argumente gibt, übergebe nur 3. Alles danach wird ignoriert / rausgefiltert.
fiveWheels = // create list with five wheels ...
car = new Car(fiveWheels[0], fiveWheels[1], fiveWheels[2], fiveWheels[3])
Wir müssen es leider so implementieren, dass Fehler abgefangen werden. ("Implementiere alle Assoziationen und deren Multiplizitäten. Wähle gegebenfalls hierfür geeignete Datentypen und dokumentiere idese. Vergesse NICHT die Fehlerbehandlung").
Assoziationen und Multipliziäten implentieren hab ich jetzt hingekriegt, fehlt nur noch das mit der Fehlerbehandlung. Unser Tutor war sich leider unsicher, ob damit gemeint ist, dass eine ein Konstruktur bspw. nicht mehr Argumente als nötig entgegen nimmt oder dass z.B. ein Parameter der falschen Klasse zugeordnet wird. Auf jeden Fall darf das Programm in diesem Fall nicht abschmieren.Wenn man jedoch mehr Parameter als nötig eingibt, macht der Python-Interpeter patsch und weißt einen darauf hin. Ich habe mir gedacht, dass an dieser Stelle dann vielleicht ein String passend wäre, der dann sagt, man habe nur max. 3 Argumente einzugeben. Tutor meinte, das gehe über try-except.
In dem Beispiel wird eine Division durch 0 mit try-except verhindert. Aber mir erschließt sich nicht, wie man eine falsche Parameterübergabe oder eine falsche Klassenzurodnung mit try-except auffangen kann.
x = 10
for y in [3, 0, 1]:
try:
z = x / y
except:
z = None
print("z: ", z)
Wenn ein Nutzer mehrere Werte in seine Tastatur eingibt, wie übergibst du diese an den Konstruktor und sorgst somit für einen Fehlerfall?
Ein try-except ist bei einer Division durch Null nicht notwendig, eine einfache Abfrage via if würde vollkommen ausreichen. Dies gilt auch in anderen Fällen - erst prüfen, ob es nicht auch mit if-else behandelt werden kann.
Danke für die sehr ausführliche Antwort, das ist mehr als ich gedacht habe. :) Wirklich sehr gute und anschauliche Darstellungen.
Der Unterschied von Aggregation und Komposition ist mir bekannt, aber mir fällt halt kein Ansatz ein, wie ich die Aggregation zwischen Presenter und Member in Python initalisieren soll. Bei Vererbung ist es ja verhältnismäßig einfach - da schreibt man einfach die Elternklasse in Klammern hinter der Kindklasse
class Professor (Member).
Aber wie mache ich es in Quellcode deutlich, das hier speziell eine gerichtete 1,* Assoziation von Presenter zu Member besteht?