UML Diagramm in Python umsetzen?

1 Antwort

Vom Fragesteller als hilfreich ausgezeichnet
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.


Jensek81 
Fragesteller
 18.01.2019, 21:18

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?

0
regex9  18.01.2019, 21:55
@Jensek81

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
1
Jensek81 
Fragesteller
 18.01.2019, 23:42
@regex9

Alles klar, danke.

Wie fange ich eine falsche Eingabe ab? Also wenn eine __init__() nur 3 Attribute entgegen nimmt, aber man bspw. 4 eingibt. Mit "try und expect" habe ich es probiert, aber es funktioniert nicht.

0
regex9  19.01.2019, 03:02
@Jensek81

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])
1
Jensek81 
Fragesteller
 19.01.2019, 03:31
@regex9

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)
0
regex9  19.01.2019, 03:42
@Jensek81

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.

1