So, herzlich willkommen zur Vorlesung Softwaretechnik 1.
Ich vertrete heute Professor Tichy, der Sie grüßen lässt.
Er ist auf Konferenz und deswegen müssen Sie mit uns Vorlieb nehmen.
Wir fangen die Vorlesung wieder mit einem Puzzler an.
Und der ist erstmal recht überschaubar.
Es gibt zwei Klassen, eine die heißt Basis und eine die heißt
abgeleitet.
Abgeleitet beerbt die Basisklasse.
Und in der oberen, in der Basisklasse gibt es eine Instanzvariable mit
dem Namen Basis.
Die ist öffentlich zugänglich.
Und in der Unterklasse gibt es auch eine Variable, die den Namen
enthält.
Die ist namensgleich, heißt auch Name.
Die ist aber private.
Und naja, es gibt natürlich wie immer so eine Main-Methode, die das
Ganze dann ausführt.
Da wird eine neue, abgeleitete Klasse angelegt, instanziiert.
Und der Name, der wird angezeigt.
Und jetzt ist die Frage, was passiert hier?
Was wird denn angezeigt?
Wird Basis ausgegeben oder wird abgeleitet ausgegeben?
Oder gibt es einen Laufzeitfehler oder einen Übersetzerfehler?
Schauen Sie sich das Ganze mal kurz an.
Denken Sie nach, was so alles erlaubt ist in Java und was verboten
ist.
Hier nochmal die drei Möglichkeiten.
Wer ist denn für einen Übersetzerfehler?
Das sind ein paar.
Wer ist für Basis?
Das sind deutlich weniger.
Und wer ist für abgeleitet?
Das sind ungefähr genauso viele.
Also recht haben die Leute, die sich bei übersetzt nicht gemeldet
haben.
Die Frage ist, warum übersetzt dieses Beispiel nicht?
An welcher Stelle bekommt man denn einen Übersetzerfehler?
Wer möchte da denn was zusagen?
Ja.
Okay, der Kommilitone sagt, ich hoffe, ich zeige jetzt auf die
richtigen Teile.
Hier entsteht der Fehler, weil ich habe ja zweimal dieselbe Variable
deklariert.
Und das ist in Vererbung irgendwie böse.
Hat jemand eine andere Meinung, eine andere Stelle?
Aha, also der Kommilitone sagt, wir deklarieren in der abgeleitet das
Ganze als private.
Und genau weil das private ist, kann man hier unten in der Main
-Methode nicht drauf zugreifen.
Und deswegen scheitert es an dieser Stelle.
Und damit hat er recht.
Das ist natürlich eine blöde Idee.
Wenn man das haben wollte, dass das geht, dann müsste man Getter und
Zetter -Methoden anbieten.
Gegenfrage, dürfte ich eine Getter-Methode machen, GetName, die in
Basis public ist und in abgeleitet private?
Darf ich sowas machen?
Also ich sage Ihnen erstmal noch was zu den Variablen.
Wir haben hier eine Verdeckung.
Die String-Variable, die wir in der abgeleitet Klasse haben, die
verdeckt die Variable in Basis.
Deswegen übersetzt es hier.
Also wir haben keinen Fehler in der abgeleitet Klasse, wie der erste
Kommilitone das angemerkt hat.
Sondern wir haben tatsächlich erst beim Aufruf das Problem.
Und jetzt die Folgefrage war, kann ich denn ein Getter deklarieren?
Einmal public und einmal private.
Also im gleichen Schema.
Oben public und unten private.
Wer ist denn für ja, das darf man machen?
Wer ist für nein, das geht überhaupt gar nicht?
Okay, wir haben jetzt, ich schätze mal 5 gegen 15.
Wir müssen sich noch ein bisschen mehr beteiligen.
Was man tun kann, um an diese verdeckte Variable dran zu kommen, ist
zu casten.
Das heißt, ich kann aus dieser abgeleitet Klasse wieder eine Basis
-Klasse machen.
Und dann kriege ich den Zugriff.
Das heißt, da komme ich an der Verdeckung vorbei.
Aber die Frage ist, was passiert, wenn ich das so mache?
Das ist jetzt beides public.
Haben wir das ausprobiert mit public und private?
Nee.
Also die 15, die gesagt haben, das darf man nicht, die haben recht.
Sie dürfen die Sichtbarkeit von Methoden nicht einschränken.
Weil wenn Sie eine Methode in der oberen und unteren Klasse
deklarieren, dann überschreiben Sie die.
Und beim Überschreiben dürfen Sie die Sichtbarkeit nicht ändern, beim
Verdecken schon.
Das heißt, wenn Sie die Variable haben, im ersten Beispiel, da haben
Sie verdeckt, das ist zulässig.
Hier wird überschrieben, das geht nicht.
Wenn man jetzt die Klassen so implementiert, mit zwei öffentlichen
Gettern, was kommt denn dann raus, wenn man sich eine neue abgeleitet
Klasse anlegt und dann GetName aufruft?
Was kommt bei diesen beiden Beispielen raus, die jetzt in dieser
Sprechblase dran sind?
Wer glaubt, da kommt einmal abgeleitet und einmal Basis raus?
Jetzt mal, das sind so 20, 25.
Wer glaubt, da kommen zweimal Basis raus?
Das glaubt keiner, okay.
Wer glaubt, es kommt zweimal abgeleitet raus?
Das sind vielleicht auch so 20.
Das heißt, wir haben einen Gleichstand zwischen abgeleitet und Basis
und zweimal abgeleitet.
Und recht haben hier die, die sagen, da kommt zweimal abgeleitet raus,
obwohl man unten castet.
Da kommt zweimal dasselbe raus, es wird zweimal dieselbe Methode
aufgerufen, weil auch wenn Sie hier im unteren Fall nach Basis casten,
haben Sie eine Instanz der Klasse abgeleitet in der Hand.
Und deswegen wird auch die entsprechende Implementierung aufgerufen.
Als Moral, Verdecken ist eine schlechte Idee.
Also Sichtbarkeit ändern bei Variablen und generell die Variablen
verdecken, das sollten Sie bleiben lassen.
Dass das geht, heißt nicht, dass man es tun sollte.
Vielleicht finden Sie einen Use Case, wo das wirklich nützlich ist,
aber in der Regel ist das böse, wenn sich die abgeleitete Klasse
anders verhält, als die, von der Sie erbt.
Es gibt noch andere Möglichkeiten, wo man etwas verdecken kann.
Man kann Typinformationen ändern, man kann einmal ein Klassenattribut
statisch deklarieren und einmal als Instanzvariable usw.
Das sind alles Dinge, die man machen kann, aber nicht tun sollte.
Insofern versuchen Sie sauber einen Code zu schreiben, dann wird alles
ein bisschen besser.
Sie haben in der letzten Vorlesung, die ist schon ein paar Tage her,
fast zwei Wochen, mit Professor Tichy besprochen, wie man ein
Klassenmodell erstellen kann.
Wie komme ich zu einem guten Objektmodell?
Sie haben besprochen, dass man Klassen findet, indem man nach
Substantiven sucht und Beziehungen findet, z.B.
bei der Formularanalyse usw.
Heute werden wir uns anschauen, wie man Attribute finden kann.
Attribute von Klassen finden Sie auch, wenn Sie sich Dokumente
anschauen, z.B.
wenn es ein Papierformular gibt für die Anmeldung, dann stellen Sie
fest, für eine Anmeldung brauche ich bestimmte Informationen.
Ich muss z.B.
eintragen, wo ich mich anmelde, für welchen Kurs usw.
Und damit kommen Sie ganz gut durch.
Was Sie entscheiden müssen ist, ist dieses Attribut, das ich hier
gefunden habe, überhaupt relevant?
Möchte ich das haben in meinem Software-System oder nicht?
Und Sie sehen das z.B.
daran, wenn Sie ein Attribut identifizieren und feststellen, das
kriegt überhaupt nie einen Wert.
Das ist immer auf dem Standardwert z.B., dann ist das irgendwie blöd.
Das Gleiche gilt für Attribute, die man niemals in der grafischen
Benutzeroberfläche sieht.
Das ist vielleicht auch nicht unbedingt ein Attribut.
Wenn Sie etwas nur ins Klassendiagramm eintragen, weil Sie wissen,
dass Sie das in der Implementierung brauchen, dann ist es kein
Attribut.
Dann ist es ein Implementierungsdetail.
Implementierungsdetails haben im Modell nichts verloren.
Sie machen auch keine Liste von Objekten als Attribut irgendwohin,
wenn Sie wissen, ich habe hier eine Relation und das speichere ich
später in der Liste.
Das machen Sie nicht.
Es reicht, wenn Sie den Strich zwischen die zwei Klassen ziehen und
der Implementierer, der Entwickler, der muss dann später entscheiden,
macht er das mit einer Liste oder macht er vielleicht eine Hashmap
oder was auch immer.
Sie tragen das nicht ein, weil es ist ein Implementierungsdetail.
Dann müssen Sie sich noch entscheiden, ob so ein Attribut, das Sie
gefunden haben, tatsächlich zu einer dieser Klassen gehört, die Sie in
der Hand haben oder ob es vielleicht zu einer Assoziation gehört.
Wir haben das in der Seminarorganisation gesehen.
Da gibt es Assoziationen, die noch Zusatzinformationen brauchen.
Und diese Zusatzinformationen, die gehört eben an die Beziehung dran
und nicht an die Klasse selbst.
Wenn diese zwei Klassen, die Sie haben, mehrfach miteinander in
Beziehung stehen können und Sie haben das als Attribut in der Klasse
geschrieben, dann können Sie halt tatsächlich nur eine Relation
aufbauen, weil für die zweite können Sie die Zusatzinformationen nicht
mehr ablegen.
Also da müssen Sie entscheiden, gehört es zu der Klasse, die ich in
der Hand habe oder gehört es zu einer Beziehung.
Und wenn es zu der Beziehung gehört, dann brauchen Sie im Modell
nichts weiter tun, als das da dran schreiben.
Wenn Sie es implementieren später, dann brauchen Sie eine Klasse, die
diese Beziehung repräsentiert, weil Sie die Zusatzinformationen
irgendwo speichern müssen.
Wenn Sie ein Attribut haben, dann müssen Sie diesem Attribut natürlich
auch einen Namen geben.
Dieser Name, der soll idealerweise ein Substantiv sein oder noch ein
Adjektiv davor haben.
Und dieses Substantiv, das soll sprechend sein.
Das heißt, wenn jemand dieses Substantiv liest, dann soll er wissen,
was in diesem Attribut drin steht.
Und erst wenn Sie das getan haben, dann überlegen Sie sich den Typ.
Zum Beispiel, wenn Sie die Telefonnummer speichern, ist es
wahrscheinlich nicht so furchtbar sinnvoll, das als Integer zu
speichern.
Das ist vielleicht auch nicht eine gute Idee, die Zeichenkette
speziell irgendwie runterzubrechen, dass Sie sagen, okay, ich brauche
hier immer ein Plus und dann kommt ein Country Code, der hat in der
Regel zwei Stellen.
Dann kommt eine Vorwahl und da müssen Klammern drumherum sein.
Das wollen Sie vermutlich an der Stelle nicht machen, sondern Sie
wollen das als Zeichenkette speichern und beim Eintragen, beim Belegen
dieses Attributs prüfen, ob die Eingabe einem gewissen Schema
entspricht oder nicht.
Und dann entsprechend an den Benutzer zurückmelden, sorry, hier fehlt
der Country Code.
Aber Sie wollen das vermutlich nicht in dem Attribut vernageln.
Vorhin bei dem Puzzler hatten wir diesen einen Punkt.
Man kann ja Static an so einer Variable dranschreiben.
Wenn Sie das tun, dann ist das eine Klassenvariable und alle
Instanzen, die Sie von dieser Klasse anlegen, die bekommen in der
Variable denselben Wert.
Und zwar nicht als Initialisierung, sondern das ist tatsächlich immer
dieselbe Referenz auf denselben Eintrag.
Wenn Sie sich zwei Instanzen holen und Sie haben so ein statisches
Attribut und Sie ändern das bei einer, dann ändert es sich bei der
anderen mit.
Weil das ist ein Attribut von der Klasse und nicht von der Instanz.
Und das sind Dinge, die Sie auch beim Modellieren betrachten müssen.
Und nur dann macht es Sinn, was da reinzuschreiben.
Die Beispiele, ich weiß nicht, ob die so furchtbar griffig ist, die
Anzahl aller Ecken, also der Ecken aller Rechtecke ist vier.
Das stimmt schon, aber ich würde mir die Anzahl Ecken wahrscheinlich
nicht in der Instanzvariable oder in der Klassenvariable speichern.
Das ist vermutlich nichts, was ich brauche.
Wenn ich aber eine Anwendung habe, die wissen will, dieses 2D-Objekt,
das ich hier zeichne, wie viele Ecken hat das eigentlich?
Dann muss ich das irgendwo ablegen.
Und dann ist der richtige Ort die Klasse.
Und das brauche ich nicht in jeder Instanz separat speichern, sondern
das reicht tatsächlich, wenn ich das einmal tue.
Attribute, die Sie nur brauchen, um eine Instanz zu identifizieren,
die werden in der Regel nicht eingetragen.
Das heißt, stellen Sie sich vor, Sie modellieren eine Datenbank und
Sie haben irgendwo gelernt, ich brauche einen Primärschlüssel und dann
nehme ich einfach eine fortlaufende Nummerierung.
Dann ist das in der Datenbankwelt völlig richtig.
Aber wenn Sie diese Tabelle jetzt abbilden auf eine Java-Klasse zum
Beispiel, dann würden Sie vermutlich für diesen Primärschlüssel keinen
Eintrag als Attribut explizit modellieren.
Das brauchen Sie an der Stelle nicht.
Nichtsdestotrotz werden Sie vermutlich diese Information irgendwo
brauchen.
Spätestens, wenn Sie eine Änderung an diesem Datensatz in die
Datenbank zurückschreiben wollen.
Dann brauchen Sie die ID vielleicht trotzdem.
Dann ableiten von Attributen.
Das heißt, wenn Sie mehrere Attribute haben, die im Kern dieselbe
Information tragen, dann ist natürlich fraglich, ob Sie beide
speichern müssen.
Beispiel ist hier mit Alter und Geburtsdatum gemacht.
Wenn Sie das Geburtsdatum speichern und Ihr System das aktuelle Datum
kennt, können Sie natürlich das Alter ausrechnen.
Jetzt können Sie sich sagen, okay, ich spare mir den Speicher, weil
Speicher ist furchtbar teuer oder ich habe furchtbar viele Instanzen,
die ich anlege.
Ich berechne das immer, wenn ich es brauche.
Dann ist das eine Entwurfsentscheidung, die Sie treffen können und
dann ist die richtig für Ihren Kontext.
Es könnte aber sein, Speicher ist furchtbar billig oder Sie haben sehr
wenig Instanzen.
Sie brauchen aber sehr, sehr oft diese Altersinformationen.
Dann wollen Sie die vermutlich nicht ausrechnen.
Dann würden Sie zwei Attribute anlegen.
Das heißt, hier müssen Sie immer betrachten, was ist der Zweck?
Warum habe ich dieses Attribut?
Wie oft brauche ich das?
Wofür brauche ich das?
Dann müssen Sie entscheiden, ob Sie es explizit in das Modell
aufnehmen oder ob man es implizit berechnen kann, indem Sie ein Getter
dafür hinschreiben und in einem Kommentar vermerken, das Alter
berechnet sich aus dem Geburtsdatum, steht in einem anderen Attribut
und dem heutigen Datum.
Wenn Sie so etwas haben, was voneinander abhängt, dann achten Sie
darauf, dass die Konsistenz erhalten bleibt.
Das heißt, wenn jemand das Geburtsdatum ändert und Sie haben das Alter
explizit gespeichert, dann muss die Methode, die das Geburtsdatum
aktualisiert, auch das Alter aktualisieren.
Umgekehrt wird es vermutlich nicht gehen, wenn jemand das Alter
ändert, das Geburtsdatum rausraten.
Das ist hochgradig schwierig.
Da brauchen Sie noch Zusatzinformationen, die Sie vermutlich nicht
haben.
Aber da müssen Sie darauf achten und am besten schreiben Sie das dann
auch auf, dass diese beiden Attribute was miteinander zu tun haben.
Und was?
Was ist die Abhängigkeit?
Welches ist das Hauptattribut und welches ist nur abgeleitet?
In dem Fall wäre das Geburtsdatum das Hauptattribut.
Bestehend Zweifel darüber, ob Attribute einer bestehenden Klasse
zugeordnet werden oder ob eine neue Klasse gebildet wird, dann bilden
Sie eine neue Klasse.
Steht da so lapidar.
Kann sich jemand vorstellen, wann das der Fall ist, dass ich nicht
genau weiß, ob ich das hier dazuschreiben soll oder nicht?
Vielleicht hat jemand eine konkrete Idee.
Stellen Sie sich vor, Sie modellieren ein System, in dem es um
Personen geht.
Und wir nehmen jetzt hier nicht das untere mit der Adresse, sondern
Sie modellieren einmal allgemein Personen.
Eine Person hat einen Namen und ein Geburtsdatum und vielleicht eine
Schuhgröße.
Und dann stellen Sie fest, hier gibt es auch noch Kunden.
Kunden haben eine Kundennummer und vielleicht eine Liste von
Bestellungen, die Sie aufgegeben haben.
Und es könnte sein, dass Sie Personen in Ihrer Anwendung verwalten,
die noch keine Kunden sind.
Und dann wollen Sie vermutlich die Kundennummer nicht bei der Person
ablegen, sondern Sie wollen tatsächlich einen Kunden explizit
modellieren.
Wenn Sie z.B.
die Idee kriegen, ich habe hier eine klasse Person und jetzt mache ich
da ein bulsches Flag.
Ist Kunde oder ist kein Kunde?
Und wenn ist Kunde oft true ist, dann muss die Kundennummer belegt
sein.
Das ist irgendwie Quatsch.
Machen Sie dann eine abgeleitete Klasse, fügen Sie der Unterklasse,
dem Kunden, das Attribut hinzu.
Und dann wissen Sie, wenn Sie einen Kunden in der Hand haben, dann ist
es ein Kunde und dann hat er auch eine Kundennummer.
Wenn Sie eine Person in der Hand haben, dann nicht.
Dann können Sie unterscheiden.
Machen Sie das nicht über irgendwelche Kodierungen in Attributen.
Das ist eine schlechte Idee.
Wenn wir beim gleichen Beispiel bleiben, wenn eine Person eine Adresse
gespeichert bekommen soll, dann können Sie natürlich hingehen und
dieser Person-Klasse ein Feld geben für eine Straße und ein Feld geben
für die Postleitzahl und für den Ort und für das Land.
Und dann hat die Person alle Attribute, die man braucht, um eine
Adresse zu speichern.
Ist das eine gute Idee?
Das ist eine Suggestivfrage.
Und die Antwort steht schon auf der Folie.
Ich frage mal den ganz beteiligten Studenten hier vorne, ist das eine
gute Idee, das zu tun?
Jetzt vielleicht die interessantere Frage.
Warum ist das eine schlechte Idee?
Da würde ich jetzt gerne ein bisschen Input von Ihnen bekommen.
Die habe ich gesehen und ich nehme sie gleich dran, aber ich will noch
eine zweite Hand sehen.
Danke schön.
Ihr Kommilitone sagt, es wäre wahrscheinlich geschickter, aus der
Adresse eine ganze Klasse zu machen.
Das steht auch schon auf der Folie.
Wenn ich das nicht tue, wenn ich das einfach als Attributliste in die
Person rein drücke und ich ändere die Adresse, dann muss ich mir über
Konsistenz Gedanken machen.
Wenn jetzt jemand eine komplett neue Adresse bekommt, der zieht in ein
anderes Land, dann ändere ich erst mal vielleicht das Land.
Dann habe ich das getan und dann steht da am Fassadenkarten 5 in
Frankreich.
Das ist blöd.
Das heißt, ich habe hier einen inkonsistenten Zustand und muss
sicherstellen, dass niemand die Adresse liest, während ich die noch
ändere.
Wenn das nur ein Attribut ist vom Typ Adresse, dann kann ich einfach
eine neue Adresse instanziieren und die austauschen gegen die alte.
Oder die alte gegen die neue austauschen.
Dann habe ich instantan den Wechsel und alle Attribute, die semantisch
zusammengehören, also Straße, Postleitzahl, Ort, Hausnummer, Land, die
sind atomar geändert worden.
Es ist ja auch nur noch ein Eintrag in der Personeninstanz.
Und das ist das, was man haben will.
Man möchte immer semantisch zusammengehörende Dinge auch zusammen
ablegen.
Und das heißt nicht, die stehen im Quelltext in benachbarten Zeilen,
sondern das heißt bei der Modellierung immer, es ist in einer Klasse
zusammengefasst.
Ist Ihnen das klar?
Ich hoffe schon.
Wenn nicht, müssen Sie mich unterbrechen.
Jetzt kommt der Schritt, wo Sie Vererbungsbeziehungen einführen.
Bis dahin haben wir nur Klassen modelliert und die Beziehungen
dazwischen hergestellt und die Attribute uns ausgedacht, aber wir
haben noch keine Vererbungsbeziehungen.
Und Vererbung ist das, was man so intuitiv erstmal haben will, weil
das spart Schreibarbeit.
Aber Schreibarbeit sparen ist nicht der Zweck von Vererbung.
Wir müssen darauf aufpassen, dass wenn Sie eine Vererbungsbeziehung
haben, dieses Substitutionsprinzip gilt.
Und das heißt, eine Instanz von der Unterklasse, die muss exakt so
verwendbar sein wie eine Instanz der Oberklasse.
Und das heißt, wenn ich mir diese Vererbungsbeziehung gerade ausdenke,
dann muss ich sicherstellen, dass das eben der Fall ist.
Ich muss zeigen können, jedes Mal, wenn ich eine Instanz der Klasse B
habe, dass das auch funktioniert wie eine Instanz der Klasse A.
Also ein Kunde funktioniert immer genauso wie eine Person, nur er hat
ein bisschen mehr.
Dann kann ich das machen.
Wenn ich mich hinstelle und sage, ich habe hier ein Zeichenprogramm
zum Beispiel und es gibt einen Punkt, der hat X- und Y-Koordinaten und
es gibt eine Linie.
Na ja, gut, für eine Linie brauche ich zwei Punkte, also zwei X- und
zwei Y-Koordinaten.
Dann sage ich, gut, dann mache ich da eine Vererbungsbeziehung, weil
dann spare ich mir ja den einen Punkt.
Der ist ja im Punkt schon definiert.
Ist das eine gute Idee?
Natürlich nicht, weil eine Linie ist kein Punkt.
Das ist das, was das heißt.
Wenn Sie sagen, Linie erbt von Punkt, dann heißt das, jede Linie ist
ein Punkt.
Und das ist offensichtlich falsch.
Ihr Kommilitone fragt, was mache ich denn, wenn ich eine Basisklasse
habe, die ich gar nicht instanziieren darf, weil es zum Beispiel einen
privaten Konstruktor gibt.
Die fasst nur Dinge zusammen, die ich eben zusammenfassen muss.
Der Initialisierungsaufwand ist irgendwie schwierig.
Ein privater Konstruktor heißt nicht, dass sie keine Instanz haben.
Vermutlich kann man die Klasse trotzdem instanziieren, zum Beispiel
über eine Fabrikmethode, die dann genau diesen Initialisierungsaufwand
durchführt.
Eine Klasse, von der es keinerlei Instanzen gibt, das ist nur eine
Datensammlung.
Die lebt ja nicht wirklich.
Und auch dann können Sie vererben.
Sie müssen halt sicherstellen, dass derjenige, der erbt, die
Spielregeln hält.
Und in gewisser Weise werden Sie vom Übersetzer unterstützt, weil Sie,
wenn Sie den Konstruktor aufrufen, irgendwann auch mal super aufrufen
sollten.
Aber letztendlich bleibt es Ihrer Modellierung überlassen, was Sie da
genau tun.
Das Substitutionsprinzip gilt dann immer noch.
Stellen Sie sich vor, Sie haben eine Oberklasse, die eine
Datenbankverbindung kapselt.
Und die hat auch keinen Konstruktor, sondern die hat eine Initialize
-Methode und die gibt dann halt eine Datenbankverbindung zurück.
Dann legen Sie Unterklassen an, eine für MySQL und eine für Postgres.
Dann muss diese Initialize-Methode auch in den Unterklassen
implementiert sein und sinnvoll funktionieren.
Beantwortet das Ihre Frage?
Dieses Substitutionsprinzip, das ist ziemlich hart.
Und wenn Sie sich an dieses Prinzip halten, dann stellen Sie fest,
dass in einem Entwurf relativ wenig Vererbung stattfindet.
Also das ist keine Vererbungshierarchie mit 17 Ebenen, sondern das ist
eher eine flache Hierarchie mit vielleicht zwei, drei, vier Ebenen.
Aber die ist sehr breit.
Das heißt, es gibt viele Geschwister und es gibt viele Beziehungen
zwischen den Klassen.
Aber Vererbungsbeziehungen gibt es in der Regel nicht so viele.
Oder deutlich weniger, als man erst mal intuitiv hinmalen will.
Denken Sie daran, Vererbung ist nicht dazu da, in Schreibarbeit zu
sparen.
Das passiert da auch, aber das ist nicht der Zweck.
Wenn Sie jetzt eine Menge von Klassen haben, dann schauen Sie sich die
an und versuchen, diese Ober- und Unterklassebeziehungen herzustellen.
Und dann können Sie sich natürlich überlegen, wenn Sie mehrere Klassen
haben, die Geschwister sind, und es gibt eine Oberklasse, dann ist
natürlich die Frage, welche Attribute und Methoden, also Operationen,
sind in der Oberklasse drin.
Sollte die Oberklasse abstrakt sein?
In dem Datenbankbeispiel von eben ist wahrscheinlich diese allgemeine
Datenbankconnection, die ist vermutlich abstrakt.
Mit der kann ich nichts anfangen, ich brauche immer eine konkrete
Implementierung.
Das müssen Sie sich überlegen.
Es könnte auch sein, Sie haben schon eine Oberklasse und stellen fest,
da passt noch ein Kind dazu, das kommt auch durchaus vor.
Und da können Sie natürlich schauen, gibt es Überlappungen, was die
Attribute angeht.
Gibt es ganz viele Klassen, die haben einen String mit Name und
Vorname, dann sind das vielleicht alles Personen, auch wenn die
unterschiedlich ausgeprägt sind letztendlich.
Und wenn Sie eine sehr große Klasse haben, die ganz viele Attribute
hat und ganz viele Operationen, dann können Sie sich auch überlegen,
ob man diese Klasse aufspalten kann.
Es gibt später, wenn Sie in den fortlaufenden Vorlesungen unterwegs
sind, es gibt Bad Smells, nicht nur auf Code-Ebene, das heißt, wenn
sich jemand nicht an Coding-Conventions hält, es gibt es auch für die
Modellierung.
Und ein Smell ist da die Gott-Klasse.
Das ist einfach eine Klasse, die hat alle Operationen, die man so
brauchen könnte, so das Schweizer Taschenmesser.
Und es ist aber auch noch ein Fallschirm dran und ein Schlauchboot.
Vermutlich wollen Sie das nicht haben, Sie wollen das aufbrechen in
eine Schlauchboot-Klasse und eine Messerklasse und eine Sägen-Klasse
usw.
Und die spezialisierten Klassen, die können dann wirklich nur noch
das, was sie tatsächlich brauchen, um die eine Funktionalität
darzustellen.
Also, wenn Sie eine Klasse haben, die in Ihrem Modell eine 4-Seite
braucht, alleine, dann überlegen Sie mal, ob Sie die vielleicht
aufspalten können.
Und wenn Sie das getan haben, aufgespaltet und die Färbungsbeziehung
eingezogen, dann überlegen Sie nochmal, gilt das Substitutionsprinzip
noch?
Habe ich zufällig sowas gebaut wie, ein Dreieck ist eine Linie?
Das ist nämlich eine Linie mit drei Punkten und wenn man die alle
verbindet, hat man ein Dreieck.
Das ist natürlich Quatsch.
Sowas müssen Sie sich anschauen.
So, was haben wir hier?
Ein hübsches Beispiel.
Wenn Sie Färbungsbeziehungen haben, eine Oberklasse und zwei
Abgeleitete, dann sollten Sie sich die Frage stellen, ist es nötig,
die beiden Unterklassen zu unterscheiden?
Später, wenn das System läuft, gibt es irgendwas, was sich anders
verhält, wenn ich die zweite Unterklasse habe, statt der ersten?
Wenn Sie sagen, nein, da passiert immer genau dasselbe, dann sollten
Sie vielleicht nicht zwei Unterklassen haben, sondern nur eine.
Also versuchen Sie, Ihren Entwurf wieder auszudünnen.
Überlegen Sie, ist es sinnvoll, was ich hier gemacht habe?
Nicht Färbungsbeziehungen reinmachen, weil Sie irgendwann mal gehört
haben, Färbungsbeziehungen brauche ich in Objektorientierung.
Oder möglichst viele Querverbindungen reinmachen, weil das
Entwurfsmusterkapitel in der SBT, das war so dick, die muss ich
irgendwo unterbringen.
Das ist der falsche Ansatz.
Machen Sie Ihr System so schlank und so einfach verständlich wie
möglich.
Und dafür müssen Sie halt in Iterationen immer wieder mal reinschauen,
ob das noch Sinn gibt, was Sie da getan haben.
Wann haben Sie keine Vererbung?
Wenn die Unterklassen nichts Neues beitragen, dann haben Sie einfach
nur eine zusätzliche Klasse eingefügt, die Ihnen später mal Ärger
bereitet, aber das ist kein Mehrwert.
Und wenn Sie feststellen, dass zum Beispiel die Klassennamen von den
Abgeleiteten eigentlich nur Informationen darüber geben, wie die
Oberklasse gerade funktioniert, also Personen mit zweitem Vornamen und
Personen ohne zweiten Vornamen, das ist wahrscheinlich alles die
Personenklasse.
Und einmal ist halt der zweite Vorname nicht belegt.
Es ist nicht so, dass Sie dann die dritte Variable unbedingt
wegschmeißen müssen.
Da haben Sie wenig gewonnen.
Jetzt haben wir hier das Punkt- und Liniebeispiel.
Das habe ich Ihnen schon gesagt.
Der Punkt besteht aus einem Punkt, x- und y-Koordinaten.
Und bei der Linie, naja, da kriege ich jetzt noch den zweiten Punkt
dazu.
Da spare ich natürlich zwei Deklarationen, aber das ist offensichtlich
Quatsch.
Wenn irgendjemand versucht, mit einer Linie was zu machen, was man
normalerweise mit einem Punkt tut, ich weiß nicht, ob das so super
definiert ist.
Und Sie müssten sich überlegen, was dann passieren soll.
Und wahrscheinlich wollen Sie das nicht.
So, was haben wir hier?
Das hübsche Beispiel mit der Seminarorganisation.
Ich komme mal ein Stück nach hinten, damit ich das auch ernsthaft
lesen kann.
Was Sie hier sehen, ist links die Firma und rechts gibt es diese
Vererbungsbeziehung von der Person zu Kunden, Mitarbeitern und
Dozenten.
Sie erinnern sich, Kunden buchen Seminare, Mitarbeiter tun irgendwas
und Dozenten halten Seminare.
Und was es hier jetzt gibt, ist eine Aufzählung für die Rolle.
Und zwar würde ich mal sagen, ist es eine Rolle für den Mitarbeiter.
Das steht ja auch hier schön dran, nämlich die Berechtigung.
Und die Berechtigungen, die hier vergeben sind, sind
Seminarsachbearbeiter, Kundensachbearbeiter, Veranstaltungsbetreuer
und Administrator.
Und Sie können sich vorstellen, die unterschiedlichen Rollen haben
eine Auswirkung darauf, was die Instanz von dem Mitarbeiter alles tun
darf.
Ein Administrator wird einfach alles tun dürfen, aber ein
Kundensachbearbeiter darf vermutlich keine Dozenten bearbeiten.
Ein höheres Honorar eintragen zum Beispiel.
Und Sie können sich jetzt natürlich überlegen, dass unterhalb von der
Mitarbeiterklasse noch ein Seminarsachbearbeiter hängt und ein
Kundensachbearbeiter und ein Administrator.
Aber vermutlich ist die hübschere Modellierung tatsächlich hier eine
Rolle zu haben und in der Rolle zu prüfen, ob der Mensch das darf oder
der angemeldete Benutzer das darf, was er tun möchte.
Das ist ein klassischer Fall davon, dass Sie vielleicht ursprünglich
mal unterhalb von den Mitarbeitern noch aufgespalten haben, was es für
Mitarbeitertypen gibt.
Vielleicht gibt es auch noch einen Chef, aber vermutlich wollen Sie
das nur über die Rolle abbilden.
Das müssen Sie einfach überlegen, was können die einzelnen Elemente
tun, was will ich kontrollieren und kann ich vielleicht einen
Mitarbeiter vom Seminarsachbearbeiter zum Kundensachbearbeiter
befördern während der Laufzeit.
Wenn ich das tun will, dann will ich wahrscheinlich einfach nur seine
Rolle ändern.
Ich gebe ihm das Recht.
Dann ist er auch Seminarsachbearbeiter.
Ich möchte nicht, dass er sich abmeldet und nochmal neu anmeldet,
damit intern eine neue Instanz gebildet wird, die die anderen Rechte
hat.
Da müssen Sie einfach überlegen, was ist der Anwendungsfall, den ich
später mal damit abdecken muss.
Dann sind wir fertig mit dem statischen Teil.
Wir haben viele Klassen, ein bisschen Vererbung, sehr viele
Assoziationen, Operationen und so weiter.
Jetzt müssen wir irgendwas machen mit diesem System.
Das muss zum Leben erweckt werden.
Das statische Modell, das Klassendiagramm, das ist nur die Information
darüber, was für Elemente in Ihrem System existieren können.
Das zeigt nicht, was tun die Elemente miteinander.
Und dafür brauchen Sie tatsächlich dynamische Modelle.
Ganz prominent ist das Sequenz- und Aktivitätsdiagramm.
Und das ziehen Sie natürlich aus den Szenarien raus.
Im Lastenheft steht irgendwo ein Szenario.
Ein Benutzer meldet sich an, dafür gibt der Benutzer Namen und
Passwort an und dann passiert irgendwas.
Und dieses irgendwas, das passiert, das wollen Sie nicht natürlich
sprachlich beschreiben, sondern Sie möchten tatsächlich sagen, hier
kriege ich eine neue Instanz von einem Mitarbeiterobjekt.
Das erhält die Rolle Kursbearbeiter, weil das ist gerade das Szenario,
das ich durchspiele.
Und dann passieren ja Dinge.
Es werden Methoden aufgerufen, es werden Ergebnisse zurückgeliefert.
Das alles müssen Sie modellieren.
Und deswegen werden Sie vermutlich nicht ein großes Sequenzdiagramm
machen, das alles enthält, was jemals in Ihrer Anwendung passieren
kann, sondern für jeden kleinen Use-Case, für jede Alternative, die
Sie speziell betrachten wollen, machen Sie ein Diagramm.
Machen Sie nicht eins mit 47 Alternativen, sondern machen Sie
vielleicht 47 Diagramme.
Wahrscheinlich ist das schon zu viel, aber versuchen Sie nicht, alles
in ein Diagramm reinzudrücken, weil dieses dynamische Modell heißt
nicht, exakt so funktioniert die Software und auf gar keinen Fall
anders, sondern das heißt, in diesem Anwendungsfall, in diesem
Szenario ist der Ablauf der Methodenaufrufe folgendermaßen und ich
erwarte die folgenden Ergebnisse.
Und Sie können da, wenn Sie zum Beispiel die Telefonnummer abfragen,
um die anzuzeigen in der grafischen Oberfläche, können Sie in dem
Sequenzdiagramm dazu tatsächlich hinschreiben, welche Telefonnummer
zurückgeliefert wird von der Datenbank, auch wenn Sie gar nicht
wissen, was da drin steht.
Das ist nur ein Modell, das verdeutlichen soll, wie ist das zu bauen,
wie funktioniert die Mechanik von dem statischen Modell, weil im
Klassendiagramm sehen Sie nicht, was passiert.
Sie sehen nur, wie die Struktur ist.
Und in den dynamischen Modellen sehen Sie genau das, was passiert.
Ein Punkt steht hier unten noch ganz wichtig.
Positive und negative Fälle unterscheiden.
Denken Sie zurück an die Anmeldung.
Ein Benutzer meldet sich am System an und dann passiert irgendwas.
Das ist der Standardfall, den man haben will.
Der Negativfall dazu ist, er gibt das falsche Passwort ein.
Er lässt das Passwortfeld leer.
Sein Account ist abgelaufen.
Was auch immer es da für Szenarien gibt, wenn Sie eins davon in der
Hand haben, gucken Sie es an, was sind denn die alternativen Abläufe,
die es geben kann.
Benutzerkonto abgelaufen, überhaupt kein Benutzerkonto existent usw.
Dann machen Sie einfach für die interessanten Dinge jeweils ein
eigenes Diagramm.
Genau.
Wie dieses Modell aussieht, haben Sie im UML-Kapitel schon gelernt.
Insofern kommt das jetzt nicht mehr.
Die Frage ist hier eigentlich nur noch, wie kriege ich raus, was soll
ich modellieren und was soll ich nicht modellieren.
Da muss ich tatsächlich hingehen und mir den Anwendungsfall angucken.
Der steht ja im Lastenheft drin oder im Pflichtenheft.
Und dann muss ich einfach schauen, was brauche ich dafür, was muss ich
instanziieren, welche Werte muss ich dafür hernehmen.
Dann stellen Sie wahrscheinlich oder möglicherweise fest, dass Sie
einen Informationsbedarf haben, den das Klassenmodell vielleicht gar
nicht decken kann.
Sie wollen die Telefonnummer abfragen, aber es gibt keine Getter
-Methode dafür.
Das hat man halt vergessen.
Dann gehen Sie zurück ins Klassendiagramm, tragen die Getter-Methode
ein und dann können Sie Ihr Sequenzdiagramm durchmodellieren.
Das heißt, es ist nichts, was man komplett getrennt voneinander
entwirft.
Und wenn man das Klassendiagramm am Montag gemacht hat, dann darf man
am Dienstag nichts mehr ändern.
Das ist nicht die Idee.
Die Idee ist, dass Sie durch die verschiedenen Modelle verschiedene
Blickwinkel auf Ihr System kriegen und die verschiedenen Blickwinkel
sich ergänzen.
Das ist natürlich nicht nur hinterher so, wenn das Modell fertig ist
und man es liest, sondern das ist auch so, wenn es entsteht.
Und Sie müssen diese Konsistenz auch sicherstellen.
Manche Werkzeuge tun das.
Wenn Sie sagen, hier liebes Modellierungswerkzeug, das ist mein
Klassendiagramm und jetzt machen wir mal ein Sequenzdiagramm und Sie
sagen, euer Methodenaufruf mit GetFu und GetFu ist halt nicht
deklariert, dann können Sie das gar nicht tun.
Wenn Sie das mit einem Zeichenprogramm machen oder mit Papier und
Bleistift, dann müssen Sie selber sicherstellen, dass da Konsistenz
herrscht.
Das ist ein recht wichtiger Punkt.
Und auch wenn Sie beispielsweise, das ist eigentlich falsch, wenn Sie
in der Übungsaufgabe oder in der Klausur ein Klassendiagramm geliefert
kriegen und vielleicht vier Zeilen Pseudocode für eine Methode und
dann steht da lapidar, zeichnen Sie das Sequenzdiagramm.
Dann benutzen Sie in diesem Sequenzdiagramm bitte exakt die
Bezeichner, also Methodennamen, Attribute, Klassennamen, wie sie in
dem Klassendiagramm auch angegeben sind.
Nur das ist definiert, alles andere passiert in Ihrem Kopf und in der
Klausurkorrektur haben wir Ihren Kopf nicht zur Hand.
Dann müssen wir das nehmen, was auf dem Papier steht.
Wenn Sie später mal ein Systemmodell bauen und Sie werfen das nach
Indien zum Implementieren, dann haben die Ihren Kopf auch nicht zum
Nachfragen, wie das gemeint ist.
Und wenn die feststellen, da ist irgendwas komisch und Sie fragen
nach, dann haben Sie Glück gehabt.
In der Regel ist es so, dass Sie es trotzdem bauen.
Und Sie können sich überlegen, was dann passiert.
Sie kriegen irgendwas, was mit Biegen und Brechen funktioniert, aber
es tut halt nicht das, was Sie eigentlich haben wollten.
Also da müssen Sie einfach aufpassen, dass die Dokumente, die Modelle,
die Sie bauen, in sich stimmig sind und dass die auch alle
zusammenpassen.
Insbesondere, wenn Sie das eine Modell auf Deutsch machen, dann können
Sie nicht das andere auf Englisch hinschreiben.
Oder umgekehrt.
Das ist einfach eine blöde Idee.
Das muss zusammenpassen, selbst wenn das 1 zu 1 wörtlich übersetzt
ist.
Geht nicht.
Was haben wir noch?
Der Objekt-Lebenszyklus, das ist auch noch ein Blickwinkel, den man
haben kann.
Stellen Sie sich vor, Sie haben irgendein Objekt, das nicht trivial
ist, und das sind sehr wenige.
IBM sagt, das sind 1 bis 2 % der Objekte, die nicht trivial sind.
Trivial heißt, es wird erzeugt und dann ändern wir Daten drauf und
dann brauchen wir es nicht mehr und werfen es weg.
Wenn Sie ein Objekt haben, das sich anders verhält, Sie ändern
irgendeine Information, dann wechselt das den Zustand und dann kann
man es zwar mit den gleichen Methoden ansprechen, aber die machen was
anderes.
Dann müssen Sie diesen Zustandswechsel modellieren.
Stellen Sie sich vor, Sie programmieren einen Videorekorder, also die
Steuerung dafür.
Der eine Zustand ist, es liegt eine Kassette drin und der andere ist,
es liegt keine Kassette drin.
Natürlich können Sie auf die Knöpfe drücken, aber abhängig davon, ob
eine Kassette eingelegt ist oder nicht, passieren unterschiedliche
Dinge.
Das wollen Sie nicht mit If-Then-Else-Kaskaden im Quellcode abbilden,
sondern Sie wollen diesen Zustand, Kassette eingelegt, Kassette nicht
eingelegt, wahrscheinlich noch eingeschaltet, ausgeschaltet und so
weiter, explizit modellieren und dann können Sie sagen, in diesem
Zustand, bei dieser Eingabe, passiert folgende Ausgabe.
Das kann man dann auch genau so implementieren, ohne If-Then-Else
-Kaskaden oder Switches.
Versuchen Sie nicht, mit aller Gewalt irgendwo in Ihrem System ein
Objekt zu finden, das einen nicht-trivialen Lebenszyklus hat.
Das ist der unterste Punkt auf der Folie.
Es kann sein, Sie bauen ein System und da gibt es keinerlei Objekte,
für die Sie so einen Lebenszyklus modellieren müssen.
Dann ist das halt so.
Und das ist okay.
Versuchen Sie nicht, aus Ihrem Chef noch zwei Monate mehr
Modellierungszeit rauszuleiern, damit Sie irgendwo vielleicht noch was
finden, für das Sie einen Automaten bauen können.
Es kann sein, dass es keinen gibt.
Wenn Sie keinen sehen, dann sehen Sie halt keinen.
Vielleicht stellen Sie später fest, hier ist doch einer.
Dann müssen Sie halt zurückspulen und die Modellierung nachziehen.
Wie sieht das Ganze aus?
Das meiste habe ich, glaube ich, schon so händewackelnd auf der
Tonspur gesagt.
Ein Objekt, das in einem Zustand ist, das muss in diesem Zustand immer
gleich reagieren.
Wenn eine Kassette eingelegt ist und ich drücke auf Play, dann soll
das Ding abspielen.
Und zwar immer.
Dass so ein Band irgendwann mal am Ende sein kann, das ist vielleicht
noch ein anderer Zustand.
Aber solange sich der Zustand nicht ändert, reagiert das Objekt immer
gleich auf die Inputs, die von außen kommen.
Und wenn Sie feststellen, mein System kriegt in zwei Szenarien
dieselbe Nachricht, reagiert aber anders, dann ist das ein Indiz
dafür, dass Sie einen Zustandswechsel hatten dazwischen und den können
Sie dann modellieren.
Wenn Sie sowas nicht sehen, dann halt nicht.
Es kann auch sein, dass Sie einen Zustand haben, wo Sie bestimmte
Operationen gar nicht ausführen dürfen.
Kassette auswerfen, wenn keine drin ist.
Vielleicht schwierig.
Aber das System soll dann nicht abstürzen.
Deswegen müssen Sie da in der Implementierung drauf achten.
Und das ist auch wieder ein Indiz dafür, dass Sie hier zwei
verschiedene Zustände haben.
Wenn Sie ein Objekt gefunden haben, bei dem Sie zwei Zustände
identifiziert haben und Sie denken, Sie haben das super ausmodelliert,
dann gehen Sie einen Schritt zurück, gucken mal nach links und rechts,
ob es vielleicht noch einen dritten Zustand gibt.
Es ist recht wahrscheinlich, dass Sie dort Zustände finden, wo es
schon welche gibt.
Vielleicht von einem anderen Objekt sogar.
Aber wenn es hier eine Information über Zustände gibt, dann gucken Sie
mal, ob da vielleicht noch ein anderer dabei ist.
Gerade bei dem Videorekorder, Kassette drin, Kassette draußen.
Ein aus, Timer gesetzt, kein Timer gesetzt.
Seien Sie kreativ.
Sie können an der Stelle eigentlich nur gewinnen, wenn Sie Kreativität
einbringen.
Was haben wir noch?
Wenn Sie so einen Zustandsautomaten haben und eine Klasse dazu, dann
wissen Sie ja, wie viele Zustände es gibt und welche Operationen in
der Klasse definiert sind und dann müssen Sie prüfen, ist definiert
für jede Methode und jeden Zustand, was dann passieren soll.
Es könnte sein, Sie haben eine Kombination aus Methodenaufruf und
Zustand, der nicht gültig ist.
Dann notieren Sie das.
In diesem Zustand darf die Methode nicht aufgerufen werden.
Lieber Entwickler, wenn du es doch tust, dann explodiert es.
Eine Ausnahme wird ausgelöst.
Dafür gibt es auch eine, Illegal State Exception.
Schreiben Sie das einfach hin.
Und bevor Sie das ausimplementieren, überlegen Sie sich nochmal mit
der Automatentheorie, ob dieser Automat minimal ist.
Es macht keinen Sinn, einen Automat mit 48 Zuständen zu bauen.
Dann stellen Sie fest, 47 davon sind eigentlich identisch.
Außer, dass sich der Zeitstempel ändert.
Sie müssen auch da nochmal nachgucken, haben Sie das Modell nicht
künstlich aufgebläht oder versehentlich aufgebläht.
Wenn das der Fall ist, wieder vereinfachen.
Versuchen Sie immer, das einfachste System zu bauen, das das Problem
löst.
Nicht das Komplizierteste.
Das Komplizierteste hat zwei mögliche Ergebnisse, wenn es
funktioniert.
Sie werden gefeuert oder Sie sind unkündbar.
Aber dieses Unkündbar passiert nur, wenn das System funktioniert und
Sie es zum Fliegen kriegen.
Das hängt ein bisschen mit der Komplexität zusammen.
Sie haben also selbst in der Hand, ob Sie sich da auf den
Schleudersitz setzen oder nicht.
Operationen können Sie dann nochmal anschauen.
Sie können auch nochmal auf die Vererbungs-Hierarchie zurückblicken
und gucken, ob Sie noch etwas nach oben ziehen können.
Je weiter oben Sie es ansiedeln können, desto besser, weil dann sparen
Sie tatsächlich Implementierungsaufwand.
Und wenn Sie fertig sind, dann schreiben Sie bitte noch eine
Beschreibung der Operation.
Schreiben Sie auf, was da drin passiert.
Was die Eingaben sind, was die Ausgaben sind.
Vielleicht auch was ungültige Eingaben sein können.
Und was auf gar keinen Fall passieren darf.
Und dann sind Sie eigentlich relativ durch.
Wenn Sie sich noch überlegen, wie die Operationen aussehen.
Denken Sie mal an den Code, den Sie so in den letzten vier Wochen
haben anfassen müssen.
Wenn Sie eine Methode haben, die 400 Zeilen hat, dann hat
wahrscheinlich die Operation im Modell auch eine relativ längliche
Beschreibung.
Und da Sie ja als vorbildliche Ingenieure zuerst modellieren und dann
implementieren, stellen Sie dieses Problem schon im Modell fest und
sagen, okay, diese Operation macht jetzt ganz viele Dinge
nacheinander.
Das sind vielleicht einzelne Operationen, die man gegeneinander
abkapseln will.
Dann machen Sie das schon im Modell und nicht erst, wenn Sie die 400
Zeilen Spaghetti Code haben, weil dann ist es zu spät.
Dann ist es echte Mehrarbeit.
Und der Kernpunkt ist, jede Operation hat genau eine Aufgabe und die
füllt sie aus.
Wenn Sie eine Operation haben und die heißt, macht A und B und C, wenn
D oder F, aber auf keinen Fall D, dann eine riesige Parameterliste.
Das sind vermutlich verschiedene einzelne Operationen, die Sie
auseinanderziehen wollen.
Vielleicht gibt es die große Methode immer noch als
Bequemlichkeitsaufruf, aber die Einzelbausteine, die wollen Sie
gegeneinander abkapseln.
Dann haben wir im Prinzip das System sehr feingliedrig uns überlegt.
Wir haben sehr viele Klassen, die vielleicht was miteinander zu tun
haben, vielleicht auch nicht.
Was Sie dann noch tun ist, Sie nehmen diese Klassen und bilden Pakete.
Und diese Pakete, die sollten in sich irgendwie zusammenhängend sein.
Stellen Sie sich vor, Sie haben eine Benutzerverwaltung und da gibt es
dieses Seminarorganisationsbeispiel und auf der anderen Seite haben
Sie 423 Klassen, die haben was mit dem Datenbankzugriff zu tun.
Dann machen Sie da ein Paketchen drumherum.
Weil von außen ist es wahrscheinlich relativ uninteressant, wie die
Datenbank in sich strukturiert ist, wenn Sie nur der Benutzer sind von
der Datenbank.
Wenn Sie auf der anderen Seite derjenige sind, der die Datenbank baut,
dann wollen Sie da die Details sehen, aber von dem anderen System mit
den Mitarbeitern wollen Sie am besten gar nichts wissen.
Also machen Sie um das Mitarbeiterseminarsystem auch noch ein Kasten
drumherum.
Und Sie sollten diese Kästchen so machen, dass zwischen den Paketen,
zwischen den Subsystemen möglichst wenige Assoziationen laufen.
Im Idealfall nur eine.
Das werden Sie vermutlich nicht immer hinkriegen, aber Sie sollten es
hinkriegen, dass Sie nicht 47 Assoziationen durchschneiden.
Weil die muss man alle kennen, wenn man eins dieser beiden Systeme
implementiert.
Versuchen Sie die Schnittstelle möglichst klein zu halten.
Die Schnittstelle klein zu halten, das ist die schwache Kopplung.
Das ist die eine Sicht.
Die andere Sicht ist die interne.
Ein Paket intern soll möglichst stark gekoppelt sein.
Das heißt, alles, was da drin hängt, soll füreinander notwendig sein.
Sie wollen nicht ein Paket schnüren aus Datenbank und
Logdateiverwaltung.
Das eine hat was mit einem Dateisystem zu tun und das andere mit einer
Datenbank.
Vielleicht gibt es ein anderes Subsystem, das die beiden Dinge gleich
nutzt, aber es sind trotzdem zwei unterschiedliche Dinge.
Wie immer, suchen Sie sich einen aussagekräftigen Namen für dieses
Paket aus, für dieses Subsystem.
I, A, B, C oder 1, 2, 3 zu nennen, ist nicht so wirklich hilfreich.
Versuchen Sie das immer sprechend zu machen.
Was haben wir noch?
Das war die schwache Kopplung, das habe ich Ihnen auf der Tonspur
schon gegeben.
Vielleicht noch etwas zur Größe.
So ein Subsystem sollten Sie auf einer der vier Seiten beschreiben
können, wenn Sie das Klassendiagramm anschauen.
Es macht keinen Sinn, ein Subsystem aus 500 Klassen zu bauen.
Das ist vermutlich weiter gliederbar.
Sie können vielleicht auch Subsysteme zu einem Supersubsystem
zusammenfassen, also diese Pakete ineinander schachteln.
Aber wenn Sie auf der untersten Ebene sind, dann sollte man das auf
einer der vier Seiten anzeigen können.
Weil sehr viel mehr kann Ihr Kollege Freitagnachmittag eh nicht mehr
verstehen.
Und für den schreiben Sie das auf.
Versuchen Sie es so zu halten, dass man es verstehen kann, ohne ein
Jahr Ihren Entwurf zu studieren.
Genau.
Als Literatur gucken Sie sich das Kapitel 5 von Brügge an und schauen
Sie mal im Balzard vorbei, wenn Sie Zeit haben.
Da steht das Ganze nochmal ausführlich drin, insbesondere auch wieder
mit vielen Beispielen.
Wenn Ihnen das auf den Folien vielleicht nicht griffig genug ist,
gucken Sie in die Literatur.
Damit sind wir am Ende von diesem Kapitel und ich darf die Frage
stellen, hat jemand denn noch Fragen zu diesem Modellierungsteil?
Wie komme ich zu diesem Modell?
Hat jemand dazu Fragen oder Wünsche, Schmerzen oder ähnliches?
Jetzt wäre der Zeitpunkt, das zu tun oder diese Fragen zu stellen.
Okay.
Dann versuche ich jetzt mal, so schnell zu sein wie Professor Tichy
oder schneller.
Sie haben schon gelernt, wie man ein Lastenheft schreibt.
Das war in diesem Kapitel schon drin.
Das Lastenheft ist etwas gröber, etwas weniger feingliedrig und auch
nicht ganz so umfangreich wie das Pflichtenheft.
Das Pflichtenheft hat tatsächlich den Anspruch, wenn das jemand
geschrieben und fertig und abgesegnet hat, dann kann ich das in den
Briefkasten werfen und Wochen, Monate, Jahre später kommt ein Päckchen
mit dem Ergebnis.
Zwar idealerweise, ohne dass zwischen dieser Lieferung und diesem
Einwerfen in den Briefkasten Rückfragen nötig waren.
Das ist der Anspruch, den Sie im Pflichtenheft haben.
Im Lastenheft sind Sie noch nicht so weit.
Und dieses Kapitel 24 zeigt jetzt mal so ein Pflichtenheft.
Das meiste aus dem Pflichtenheft kennen Sie schon aus dem Lastenheft.
Das sind die schwarz gedruckten Dinge.
Die haben Sie schon ausführlich besprochen und die sind im Prinzip im
Pflichtenheft noch mal genauso drin, mit ein bisschen mehr Detail.
Zusätzlich gibt es noch zwei Hauptkapitel und drei Unterkapitel, die
im Pflichtenheft halt mehr drin sind.
Einmal ist es die Produktumgebung, also wo wird das Ding laufen, wenn
ich es später mal tatsächlich ausrolle.
Das werden Sie beschreiben.
Sie haben globale Testfälle, Stichwort Abnahmetests.
Die sollten Sie da drin formulieren, weil wenn Sie das Zeug
tatsächlich per Post in Indien bestellen, dann werden die genau nur
das machen, was Sie auch testen.
Deswegen müssen Sie vorher aufschreiben, was getestet werden wird, nur
dann können Sie sich beschweren.
Und bei den Modellen gibt es natürlich noch den Punkt, wir haben bis
jetzt nur Szenarien und Use Cases gemacht, die sind natürlich nur so
eine Außendraufsicht auf das System.
Im letzten Unterkapitel haben wir festgestellt, wir können ein
Objektmodell bauen, wir können ein dynamisches Modell bauen.
Das haben wir nicht gesehen, aber natürlich kann man das machen.
Man kann die Benutzerschnittstelle definieren.
Man kann Skizzen machen, wie soll die GUI aussehen, was ist da drauf,
welche Knöpfe muss es geben, welche Einstellregler soll der Benutzer
tatsächlich drehen können.
Das wird auch im Pflichtenheft vernagelt.
Sie müssen sich dieses Pflichtenheft anschauen, aber ich werde Ihnen
das hier nicht vorlesen, weil, ich mache mal die erste Folie auf, das
sollte Ihnen irgendwie bekannt vorkommen.
Oder sowas sollte Ihnen sehr, sehr bekannt vorkommen.
Und auch das hier und das und das und das.
Mit diesen ganzen F-Nummern.
Dann gab es auch noch FD für die Produkte.
Früher war da immer ein P. Jetzt war es ein F.
Es gab noch ein Präfix.
Das ist ein bisschen weiter ausformuliert, als das, was Sie schon
gesehen haben.
Das ist im Ilias drin, schauen Sie sich das an.
Machen Sie das vielleicht, bevor die Deadline vom Übungsblatt ist.
Und überlegen Sie mal,
ob hier Dinge drin aufgeschrieben sind, die Sie in Ihrem Pflichtenheft
oder Lastenheft vergessen haben.
Sie können es natürlich nicht abschreiben, weil Sie keine
Seminarorganisation beschreiben sollen.
Aber Ideen können Sie sich da sammeln.
Im Ilias gibt es auch noch ein zweites Dokument.
Das ist das Pflichtenheft für die Handyverträge.
Das schiebe ich Ihnen auch mal kurz hier rüber.
Das ist entstanden in einem Praktikum, das nicht heute stattfand,
sondern ich glaube vor Jahren.
Da ist sehr feingliedrig aufgeschrieben, was man machen kann.
Das sind hier 23 Seiten.
Da können Sie auch mal sehen, wie man das machen kann.
Gucken Sie sich das an.
Da gibt es auch lustige Dinge.
Das haben Sie alles schon mal gehabt.
Da sind viele Bildchen drin.
Und Tabellen.
Und da sind auch so was drin.
Fotos von Ideenskizzen.
Oder von Whiteboards mit Post-its.
Das können Sie alles machen.
Überlegen Sie sich einfach, was sinnvoll ist für die Anwendung, die
Sie gerade bauen.
Oder für das Szenario, in dem Sie gerade leben.
Vermutlich werden Sie sowas hier nicht nach Indien schicken.
Das ist nicht ganz das, was man sich da vorstellt unter
professionellem Arbeiten.
Insbesondere Handschrift ist so grenzwertig.
Aber stellen Sie sich vor, Sie machen das PSE nächstes Semester und
geben da was ab.
Und haben eine super tolle Whiteboard-Zeichnung entwickelt.
Machen Sie ein Foto und hängen Sie es in den Anhang.
Dann ist es da und geht nicht verloren.
Möchte jemand eine Frage stellen zu dieser unglaublich ausgefuchsten,
ausgefeilten und detaillierten Vorstellung des Pflichtenhefts?
Das hatte ich gehofft.
Wie lange habe ich gebraucht?
Sogar noch richtig was rausgeholt.
Der Chef hat anderthalb Minuten mehr gebraucht, aber der hat
tatsächlich noch mal vorgelesen, was da stand.
Nicht so ganz sinnvoll.
In der Vorlesung, in der letzten, die Professor Tichy gemacht hat, hat
er Ihnen erzählt, wie man aus textuellen Beschreibungen Entwürfe
rausziehen kann.
Ich habe das am Anfang kurz angerissen, man guckt sich Substantive an
und das werden dann wahrscheinlich Klassen und so weiter.
Und man kann das noch ein bisschen feingliedriger betrachten und das
fällt dann in die linguistische Analyse von Domänenbeschreibungen
rein.
Das ist üblicherweise das, was Sie von einem Kunden bekommen.
Sie kriegen von einem Kunden nicht ein fertiges Pflichtenheft mit
Sequenzdiagrammen.
Ein Kunde, der das machen kann, der kann es auch selber
implementieren.
Man kann natürlich sagen, der Kunde ist unternehmensintern und dann
sind Sie halt ein Auftragnehmer einer anderen Abteilung, die das
macht.
Dann kann es sein, dass Sie tatsächlich ein toll ausspezifiziertes
Ding kriegen.
Aber in der Regel wird jemand bei Ihnen anrufen und sagen, hören Sie
mal, ich habe da ein Problem und ich habe da eine Altsoftware und die
müsste mal jemand ablösen und außerdem haben wir hier diese
Laufzettel.
Und dann müssen Sie es tatsächlich selber machen.
Und die linguistische Analyse ist ein Mittel, um aus diesen
Beschreibungen, die Sie vom Kunden bekommen, ein Modell rauszuziehen.
Ein paar Dinge kommen Ihnen da schon bekannt vor.
Die Frage ist, warum macht man sowas?
Weil man den Kunden irgendwie zufriedenstellen muss.
Und das Problem, das man meistens hat, ist, der Benutzer kann das gar
nicht sagen.
Der kann Ihnen nicht sagen, ich brauche eine Instanz und die hat aber
eine Klassenvariable und da steht immer 47 drin, außer wenn der
Zustand anders ist.
Das heißt, Sie müssen hier einen Automaten modellieren.
Das wird Ihnen kein Kunde sagen, sondern der erklärt Ihnen, wie seine
Welt funktioniert.
Sie müssen aus dem, was er Ihnen da sagt, eine Software bauen.
Das heißt, das ist wahrscheinlich 80 oder noch mehr Prozent des
Gesamtprojektaufwandes.
Der ist da drin, rauszufinden, was der eigentlich haben möchte.
Eine Idee, eine relativ ergonomische Idee, die man verfolgen kann,
ist, man benutzt intern im Modell, in der Software, in der GUI,
überall genau dieselben Begriffe, wie der Kunde in seiner Welt auch
benutzt.
Es macht überhaupt keinen Sinn, einen Vorgang 48b zu nennen, wenn der
Kunde immer von Krankmeldung spricht.
Dann nennt man das Ding Krankmeldung.
Wenn der Kunde immer von Vorgang 47b spricht, dann schreiben Sie da
bitte nicht Fristverlängerung rein.
Da kriegt er Kopfschmerzen und Sie müssen ihm erklären, warum das
jetzt anders heißt.
Und das ist was, was Sie, sagen wir mal, aus Ihrem täglichen Leben mit
Rechnern schon kennen.
Wenn Sie sich ein Microsoft Word aufmachen zum Beispiel, dann gibt es
da einen Knopf, auf dem steht Schriftgröße drauf.
Wenn man da drauf drückt, dann ändert sich die Schriftgröße und nicht
was anderes.
Das ist äußerst hilfreich und das sorgt dafür, dass wir diese
Domänenbeschreibung, die wir vom Kunden bekommen, quasi nur noch
strukturieren müssen in einem Modell und dann später in der Software.
Wir müssen das nicht übersetzen in kryptische Namen, damit es
informatikerhaft aussieht.
Und die Frage ist, wie kann man diese Übersetzung möglichst effizient
machen und möglichst wiederholbar und fehlerarm, ohne was zu
übersehen.
Die abstrakte Idee, die hatten Sie schon.
Man guckt sich die Realität an, dann macht man einen
objektorientierten Entwurf davon, dann implementiert man das runter,
rollt es aus und fertig.
Das heißt, man läuft in der Abstraktion wieder rückwärts.
Ganz am Anfang steht die Realität, dann macht man ein sehr abstraktes
Modell, das implementiert man und dann lässt man diese Implementierung
laufen.
Das heißt, da haben Sie so eine Evolution.
Und die Frage ist, wie kommen wir da am besten hin.
Das kennen Sie alles schon.
Hat irgendjemand von Ihnen eine Bankkaufmannlehre gemacht oder sowas
ähnliches und sich dann überlegt, hey, Informatik studieren wäre genau
das, was ich jetzt machen will.
Irgendjemand sowas ähnliches reicht auch.
Hat jemand ein Girokonto?
Das reicht.
Weiß jemand, wie man Kreditbesicherung ausrechnet?
Schade.
Muss ich doch zur Bank.
Sie wissen nicht, was es in dieser Domäne gibt.
Es wird wahrscheinlich einen Kredit geben und einen Kreditgeber und
einen Kreditnehmer und wahrscheinlich auch eine Kreditsumme und Zins
und eine Laufzeit.
Das sind so die Dinge, die man kennt.
Vielleicht auch aus der Autowerbung.
0% Finanzierung, 36 Monate, 49 Euro.
Und am Ende muss man noch 100.000 Euro nachzahlen.
Aber wenn Sie eine Software dafür bauen, dann müssen Sie es ein
bisschen genauer wissen.
Und natürlich können Sie hingehen und Sie können einfach Experte
werden.
Sie haben Ihren Master in Informatik gemacht und sagen, zack, ich baue
jetzt eine Banksoftware.
Also erstmal Bankerlehre.
Und dann hocharbeiten, bis man in der Kreditsicherungsabteilung ist
und dann sagt man, okay, war schön hier, ich verdiene jetzt 180.000
Euro, aber ich mache jetzt doch nochmal ein Startup für
Bankensoftware.
Das ist nicht so wirklich tragfähig.
Und das können Sie auch nicht vermitteln.
Irgendwann müssen Sie sich halt mal festlegen.
Und deswegen gibt es kaum Software-Ingenieure, die beides können.
Es gibt sehr wenige Leute, die sind gute Software-Ingenieure und
Fachexperte für was anderes.
Da gibt es recht wenige von.
Und umgekehrt, wenn Sie einen Domänexperten herholen, so einen
Bankberater, der seit 10 Jahren Kreditabsicherung macht, der kann
Ihnen wahrscheinlich keine Software bauen.
Der kann Ihnen auch kein Software-Modell bauen.
Und deswegen müssen Sie sich irgendwie mit dem auseinandersetzen.
Aber von dem kriegen Sie eine Domänenbeschreibung.
Weil das kann er, das ist sein Fachgebiet.
Und mit der müssen Sie dann weiterarbeiten.
Die Anfänge, und das ist zum Teil auch in dem anderen Kapitel schon
drin, sind schon relativ alt.
1983 hat mal jemand clever aufgeschrieben, wir kriegen Datentypen,
also Klassen von Substantiven, wir kriegen Variablen von direkten
Referenzen, wir kriegen Operationen von Verben und Attributen.
Und außerdem kriegen wir Kontrollstrukturen.
Wenn man sich anguckt, naja, in so einem Satz steht, wenn, dann haben
wir eine Kontrollstruktur.
Und das ist aber relativ schwammig, weil Sie müssen das durchlesen,
Sie müssen es verstehen.
Und dann müssen Sie es genauso machen.
Sie müssen den Text lesen und Sie müssen damit was anfangen.
Und wenn Sie sich nicht an die Regeln halten, oder wenn Sie sich
wortwörtlich an die Regeln halten, auch wenn es Quatsch ist, dann
kommt halt Mist bei raus.
Diese Folie, mit ein bisschen anderem Inhalt, haben Sie in dem letzten
Kapitel gesehen, bei Professor Tichy, das heißt, hier haben Sie in der
linken Spalte ein Beispiel aus einer Domänenbeschreibung, zum Beispiel
Monopoly ist ein Spiel und das kann man kaufen und empfehlen und was
auch immer.
Und dann machen Sie halt, okay, Sie stellen fest, Monopoly ist ein
Eigenname, das wird wohl ein Objekt sein und Spiel ist nur ein
einfaches Nomen, das heißt, das wird eine Klasse in meinem Modell und
vermutlich ist Monopoly eine Instanz von dieser Spielklasse.
Und so können Sie sich da durchhangeln, aber das hat mannigfaltige
Probleme, insbesondere wenn man an die Assoziationen denkt.
Stellen Sie sich vor, jemand sagt Ihnen, Sie haben hier einen Satz mit
zwei einfachen Substantiven, das heißt, das wären zwei Klassen und
dazwischen ist ein Verb, ein Prädikat, daraus haben wir ja gelernt,
das wird eine Operation oder...
steht hier gar nicht drauf, ne?
Steht ja gar nicht drauf.
Da steht nur, man kriegt Operatoren von Verben.
Was ist denn mit Beziehungen, mit Assoziationen?
Die muss man auch irgendwo herkriegen, die kriegt man auch aus Verben.
Der naive Ansatz ist, wir machen das einfach so, Subjekt, Prädikat,
Objekt.
Da machen wir zwei Klassen draus, nämlich eine Subjekt- und eine
Objektklasse und die Beziehung nennen wir so, wie das Prädikat ist.
Das funktioniert erstaunlich gut.
Sie können sich vorstellen, da steht, die Geschäftsstelle liegt in
Karlsruhe.
Zack, inmodelliert, fertig, super, wow.
Dann kommt der nächste Satz und da steht, der Angestellte eröffnet
Konten.
Dann machen Sie eine Klasse Angestellte und eine Klasse Konto und eine
Assoziation eröffnet.
Dann ist das super.
Da kann ich jetzt ganz einfach aus der Assoziation rauslesen, welche
Konten von welchem Angestellten eröffnet worden sind.
Das ist total super, das will man haben, keine Frage.
Aber mit dem Entwurf können Sie halt keine Konten anlegen, weil es
gibt keine Operation, die das tut.
Bisschen ungeschickt.
Wenn wir also die Regel umdrehen und sagen, na gut, dann machen wir
halt Methoden draus, dann funktioniert das so.
Dann kann ich tatsächlich aus dem Verb, aus dem Prädikat eine Methode
machen und dann hätte ich so etwas wie Angestellter, eröffne und als
Objekt, als Argument trage ich dann ein Konto ein.
Dann wird es registriert intern und alles ist gut.
Aber dann kann ich halt so etwas wie, die Geschäftsstelle liegt in
Karlsruhe, nicht mehr machen.
Und dann würde ich mir so etwas wie eine Regel bauen, so wie, naja,
wenn du Subjekt, Prädikat, Objekt hast, dann mach entweder eine
Prädikat, also eine Assoziation draus oder eine Methode, musst halt
gucken.
Und das musst halt gucken, das funktioniert hervorragend, wenn Sie
einen hervorragenden Analysten haben.
Wenn Sie jemanden haben, der Informatik und Softwaretechnik in einem
90 Minuten Crashkurs gelernt hat und zum ersten Mal etwas modelliert,
dann kommen Sie mit solchen Regeln nicht weit.
Wahrscheinlich kommen Sie noch nicht mal bei Leuten weit, die
Informatik studiert haben und das noch nie getan haben.
Also man braucht Übungen dafür und wenn man einen schlechten Tag hat,
dann klappt es auch dann nicht.
Und da bleibt noch so eine Frage übrig.
Wir haben im Deutschen so Dinge wie Subjekt, Prädikat, Objekt, Objekt,
Objekt, Objekt, Objekt, Punkt.
Was macht man denn damit in Gottes Namen?
Da kommen wir mit unserer Regel ja überhaupt nicht weit.
Und das ist tatsächlich ein Satz, der hier steht, ein einziger, aus
dem schönen Werk Stilkunst.
Und das Beispiel finde ich so toll, weil ich es in jedem Stilbuch als
Lektor, ich hätte es ja verbrannt, aber wenn man Stilkunst macht, dann
muss man auch mal was Längeres schreiben und hier ist die Frage, wie
modelliere ich denn sowas?
Was mache ich denn mit den anderen Objekten?
Insbesondere habe ich hier jetzt ein Prädikat und viele Objekte.
Das heißt, ich treffe einmal die Entscheidung, es wird eine Beziehung
oder eine Methode und dann mache ich das für alle Objekte durch.
Das kann ja nicht funktionieren.
Das ist irgendwie ungeschickt.
Deswegen brauchen wir was anderes.
Und was man halt feststellt ist, wenn man sowas macht und guckt
tatsächlich auf die Syntax, also auf die Grammatik, die
Schulgrammatik, die sie alle gelernt haben, dann brauchen sie einen
Entwurf, eine Domänenbeschreibung, die eigentlich schon ein Entwurf
ist.
Sie müssen von ihrem Kunden sowas verlangen wie, each adherent has one
name, has one address, has at most one phone number.
Wenn das jemand so aufschreiben kann, kann er auch ein Klassendiagramm
malen.
Dann müssen sie ihm nur sagen, machen Sie mal um die Substantive
Kästchen.
Das kriegen sie von einem Kunden nicht.
Der kann das vielleicht sogar so formulieren, wenn er das strukturiert
kriegt.
Aber der sagt, ich bin doch nicht blöd.
Ich bin hier Banker, ich mache doch hier nicht Ihre Arbeit.
Wo sind wir eigentlich?
Das hier ist ein Beispiel, schon ein bisschen älter, Ende der 80er
entstanden, aus einem Ansatz, wie man aus natürlicher Sprache Modelle
gewinnen kann.
Damals hat man gesagt, man braucht das in dieser Form.
Und das ist nicht ganz richtig.
Wir sind ein bisschen weiter mittlerweile.
Aber Sie sehen, wenn Sie sich rein auf die Syntax verlassen, dann sind
Sie relativ schnell verloren.
Und Sie kriegen so Texte sowieso nicht.
Schlimmer wird das Ganze noch, wenn Sie an Beamten- oder
Ingenieursdeutsch denken.
Ingenieure werden Sie alle malen, deswegen frage ich Sie nicht danach.
Aber wer von Ihnen hat denn Jura studiert?
Auch keiner.
Das ist genau das, was man erwartet.
Wenn man mit Jura fertig ist, dann verdient man Geld, statt etwas
anderes zu studieren.
Sie grinsen, haben Sie Jura im Nebenfach?
Komplett?
Schade.
Aber dann können Sie mir vielleicht weiterhelfen.
Hat irgendjemand recht im Nebenfach?
BGB, Grundvorlesung?
Will sich keiner outen?
Oh, einer.
Sehr schön.
Studieren Sie Informatik?
Das habe ich mir gedacht.
Sehr schön.
Also ich hatte sehr viel Spaß in den Jura-Vorlesungen.
Die sind toll.
Aber da wird man konfrontiert mit Sätzen wie diesem.
Das ist 1 zu 1 zitiert aus dem Bürgerlichen Gesetzbuch.
Aufgeschrieben schon vor, ich weiß nicht, wahrscheinlich 100 Jahren
hat man damit angefangen.
Und da steht so lapidar, der Anspruch aus einer Schuldverschreibung
auf den Inhaber erlischt mit dem Ablauf von 30 Jahren nach dem
Eintritt der für die Leistung bestimmten Zeit, wenn nicht, die Urkunde
vor dem Ablauf der 30 Jahre dem Aussteller zur Einlösung vorgelegt
werden.
Nochmal kurz drüber nachdenken.
Was war nochmal das Subjekt, das Prädikat und das Objekt in dem Satz?
Ich frage Sie jetzt nicht, weil ich will Sie nicht auf Deutsch prüfen.
Aber das hier ist das Subjekt.
Was zum Henker modelliert man denn daraus?
Machen Sie da mal bitte eine Klasse und erzählen Sie dann hinterher
dem, der es implementieren soll, was das alles macht und bedeutet.
Aber wir versuchen trotzdem mal das bisschen auseinanderzuziehen.
Und man könnte das ungefähr so modellieren.
Sie haben eine Schuldverschreibung.
Sie wissen alle, was eine Schuldverschreibung ist.
Sie haben eine Schuldverschreibung und Sie haben einen Anspruch.
Und dieser Anspruch, der kommt aus der Schuldverschreibung.
Der ist quasi die Quelle.
Der Anspruch aus einer Schuldverschreibung.
Klingt total plausibel.
Und die lautet auf den Inhaber.
Also Anspruch auf den Inhaber.
Also der Anspruch auf den Inhaber.
Und der jemand, der hat den Anspruch, der steht jetzt halt in dem Satz
nicht drin.
Haben Sie den Paragraph schon mal gesehen?
Bestimmt.
Ist das richtig?
Wenn ich so frage, ist immer die Antwort Nein.
Also das ist nicht ganz richtig.
Man könnte sich z.B.
auch überlegen, der Anspruch aus der Schuldverschreibung, das ist ja
das, was da steht, auf den Inhaber.
D.h.
hier haben wir einen Besitzer.
Die Schuldverschreibung lautet auf den Inhaber.
Und wir haben jetzt das Subjekt hergenommen und haben es einfach
zerpflückt.
Und der Anspruch, der bezieht sich hier auf irgendetwas, was halt noch
nicht da steht.
Das könnte auch richtig sein.
Ist das richtig?
Immer wenn ich so frage, ist die Antwort Nein.
Eigentlich ist es so.
Sie haben eine Schuldverschreibung, die lautet auf den Inhaber.
Der ist der Besitzer.
Und der Anspruch, der leitet sich ab aus der Schuldverschreibung.
Also so rum.
Und dieser Inhaber, der hat den Anspruch.
Das steht aber nicht im Satz.
Das muss man halt wissen und die 500 Paragraphen drumherum auch noch
gut verstehen.
Oder Jura studieren.
Hätten Sie es gewusst?
Sie müssen nicht antworten.
Er sagt, wie man damit umgeht, weiß ich, habe ich schließlich
studiert.
Aber wie man das als Modell hinschreibt?
Schwierig.
Was Sie vermutlich tun wollen, Sie wollen diesen Inhaber, der hier als
Klasse modelliert ist, das wollen wir eigentlich als Rolle
modellieren.
Das ist eine Person, die diese Rolle einnimmt.
Und diese Person kann eine juristische Person sein, eine GmbH, eine AG
oder eine natürliche Person.
Also jeder von Ihnen.
Die meisten von Ihnen werden natürliche Personen sein hier.
Ob Sie das so modellieren, wie links unten oder so wie rechts, das ist
jetzt eine Entwurfsentscheidung.
Beide sind richtig.
Es kommt darauf an, was Sie damit machen wollen.
Ich neige dazu, die untere zu nehmen.
Weil eine Person, die habe ich in meinem System.
Und die ist halt in einem Szenario Inhaber einer Schuldverschreibung.
Also nimmt diese Rolle ein.
Ich will nicht einen Inhaber instanziieren, der dann zufällig das
Gleiche ist wie eine Person, die sonst irgendwo in meinem System
rumschwirrt.
Aber das hängt davon ab, wie der Fall eben aussieht.
Sie haben also mehrere Freiheitsgrade.
Und einen schönen Kopf.
Das müssen Sie sich überlegen.
Und da kommen Sie mit Syntax halt nicht weit.
Es gibt ein anderes schönes Beispiel, das Sie in dem Kontext immer mal
wieder sehen.
Und das ist dieses hier.
Und wenn Sie sich das durchlesen, da steht im ersten Satz, the janitor
will open the door with his key.
And this key will open the door.
Und wenn Sie da Subjekt, Prädikat und Objekt suchen, dann stellen Sie
fest, hey, die Tür, der Hausmeister und der Schlüssel, die sind immer
mal Subjekt und immer mal Objekt.
Also Quelle und Ziel von dieser Open-Assoziation.
Oder die Stelle, wo wir die Open-Methode eintragen, die kann
eigentlich überall sein.
Das ist ein bisschen ungeschickt.
Und deswegen hat man damals gesagt, also 1969 Fillmore hat das gesagt,
das ist völliger Quatsch.
Lasst es bitte bleiben.
Und dann hat er was anderes nachgeguckt.
Aber was er auch gesagt hat, wir sollen halt nicht auf die Syntax
gucken, sondern auf die Semantik, die da drin steckt.
Semantik ist das, was wir im Modell darstellen.
Und wenn man die Semantik an diese Sätze hinschreibt, dann stellt man
fest, der Hausmeister, das ist immer die handelnde Person.
Und das nennen wir Argens, das ist die thematische Rolle.
Und der Schlüssel, der ist immer das Hilfsmittel, das Instrument, das
Werkzeug.
Egal, wie Sie den Satz formulieren.
Und die Tür, die wird halt immer aufgemacht, die wird behandelt, und
das nennt man Patient.
Und wenn Sie an die Sätze diese thematischen Rollen hinschreiben, dann
stellen Sie fest, dass Sie in jedem Satz diesen Objekten dieselbe
Rolle zuweisen.
Also der Hausmeister, der ist immer das Argens.
Egal, wie der Satz aussieht.
Und die konkrete Syntax, die ist damit unerheblich.
Und Sie können sich auf die Semantik konzentrieren.
Jetzt ist die Frage, können wir diese Semantik nutzen, um Modelle zu
bauen?
Vielleicht sogar nicht ganz manuell.
Was man da machen kann, ist, man kann sich überlegen, die offenen
Wortklassen, das wären irgendwie Modellelemente.
Höchstwahrscheinlich, offene Wortklasse heißt alles, was Sie durch
Wortbildungsmechanismen herstellen können.
Das ist irgendwie offen.
Also es gibt Mineral und Mineralwasser und eine Mineralwasserflasche.
Sie können beliebig diese Nomengruppe erweitern, indem Sie neue Wörter
bilden.
Das werden wahrscheinlich Modellelemente sein.
Und Adjektive, das sind irgendwie Attribute oder Parameter für
Modellelemente.
Und alles, was abgeschlossen ist, die Personalpronomen, die Artikel
usw., Präpositionen, Adverbien, das kodiert Beziehungen in diesem
Modell.
Das ist also ein anderer Blickwinkel, als wir gerade eben hatten.
Und insbesondere haben wir hier oben Nomen, Verben, Nominalfrasen,
Verbphasen, Teilsätze usw.
alle in einen Tropf geworfen und sagen, das werden mal Modellelemente.
Welche müssen wir uns jetzt noch anschauen.
Aber wir machen nicht mehr die strikte Trennung nach Substantiv wird
eine Klasse und Verb wird auf jeden Fall eine Methode.
Könnte sogar sein, wir machen aus einem Substantiv eine Methode.
Werden wir später vielleicht sehen.
Wenn wir diesen Satz hier hernehmen, Tom saw the plane flying, der ist
nicht ganz eindeutig.
Wenn Sie des Englischen mächtig sind, dann stellen Sie fest, es ist
nicht ganz klar, wer da eigentlich was macht.
Also Tom sieht, das ist auf jeden Fall wahr, das heißt wir kriegen
hier eine Methode oder eine Assoziation.
Aber the plane flying, das ist jetzt die Frage, wie modellieren wir
das.
Vermutlich werden Sie sagen, das Flugzeug fliegt, ich stehe da unten
und gucke hoch oder Tom steht unten und guckt hoch.
Und deswegen kriegt die Fly-Methode eben das Plane.
Das könnte man so machen.
Sie können aber auch sagen, das Beispiel ist auch da, wenn wir da
einen Berg hin machen, brauche ich noch die alternative
Interpretation.
Man könnte hier auch sagen, der Mensch fliegt.
Also Sie sitzen selbst in einem Flugzeug, dann heißt es Tom saw
irgendwas flying.
Sie gucken halt aus dem Fenster und da ist ein anderes Flugzeug.
Dann haben Sie die Fly-Methode beim Mensch.
Hier machen wir das intuitiv jetzt zum Flugzeug.
Und wenn ich den selben Satz grammatikalisch hinschreibe, nur Berge
einsetze statt einem Flugzeug, dann werden Sie sagen, na klar, Tom
sitzt in einem Flugzeug und er bergt das da unten.
Alles andere ist ja Quatsch.
Oder?
Sie verziehen schon das Gesicht.
Normalerweise sieht es so aus.
Wenn Sie aber zufällig James Cameron heißen, dann sind Sie echt, echt
sauer, wenn Ihnen das jemand kaputt macht.
Deswegen, an reinen Sündags, wir haben hier sogar dasselbe Verb
benutzt und dieselben Attribute drumherum und kommen zu einem anderen
Modell.
Oder wir wissen nicht, zu welchem Modell wir kommen.
Und das ist irgendwie ein Problem.
Deswegen benutzen wir diese thematischen Rollen.
Davon gibt es einen ganzen Stall voll.
Je nachdem, in welchem Fachbereich Sie unterwegs sind, finden Sie
andere thematische Rollen.
Was Sie sehr häufig sehen, ist ein Agent oder ein Agent oder ein
Handelnder.
Das ist halt der, der was macht.
Sie finden sehr häufig ein Patient oder ein Patient oder ein
Behandelten.
Das ist halt der, mit dem irgendwas gemacht wird.
Und Sie finden sehr häufig sowas wie eine Action oder eine Handlung.
Und unterscheiden tun sich da im Wesentlichen die Bezeichner, die da
dran stehen.
Das sollte Sie also erstmal nicht stören.
Und die Rollen, die ich Ihnen hier vorstelle, das ist auch nur ein
Subset von dem, was wir haben.
Aber wir wollen Sie nicht quälen und Ihnen 75 Rollen beibringen.
Das macht einfach wenig Sinn für die Vorlesung.
Aber wenn man diese Rollen an einen Satz hinschreibt, dann kann man
die eins zu eins übersetzen in ein Klassendiagramm.
Und zwar einfach, indem man diesem Schema hier folgt.
Wenn ich ein Agens finde, dann mache ich daraus eine Klasse.
Wenn ich ein Patients finde, dann mache ich daraus eine Klasse.
Wenn ich ein Actus, eine Handlung finde, dann mache ich daraus eine
Methode.
Und natürlich, wenn ich ein Actus, eine Aktion habe, dann habe ich
auch jemand, der die ausführt.
Also mache ich die Methode beim Agens rein.
Und so weiter.
Ein Beispiel wäre, Peter streicht die Wand mit einem Pinsel.
Das ist genau das gleiche Beispiel wie mit dem Hausmeister, der die
Tür aufmacht.
Und hier sehen Sie, die Modellelemente sind unterstrichen.
Und die geschlossenen Wortklassen, die Artikel, die sind nicht
unterstrichen.
Und die Präpositionen auch nicht.
Die werden wir im Modell nicht brauchen.
Die sind da einfach an einer anderen Stelle versteckt.
Und wenn man jetzt diese Übersetzungsregeln einfach stur anwendet,
dann kommt man zu diesem Entwurf.
Wir haben Peter, das ist das Agens.
Wir haben die Wand, das ist das Patience.
Wir haben ein Pinsel, das ist das Instrument.
Und außerdem haben wir noch eine Methode beim Agens, nämlich den
Actus, das ist das Streicht.
Und der Patience kann auch ein Methodenparameter sein.
Und das Instrument, das ist auch ein Methodenparameter.
Deswegen tragen wir das hier ein.
Ziemlich simpel.
Wichtig ist, diese thematischen Rollen, die beziehen sich auf den Satz
oder auf den Teilsatz.
Wenn Sie jetzt einen zweiten Satz daneben schreiben, und da ist halt
auch ein Agens drin und ein Actus, dann haben die mit diesem Patience
und dem Instrument nichts zu tun.
Das bezieht sich immer lokal auf einen abgeschlossenen Bereich.
Und man könnte sagen, das ist immer ein Satz.
Aber ich kann natürlich sagen, Peter streicht die Wand mit einem
Pinsel und Matthias hält die Vorlesung mit einem Headset.
Und dann haben natürlich der Pinsel und das Headset nichts miteinander
zu tun.
Die Rollen leben nur in den jeweiligen Teilsätzen.
Das müssen Sie sich klar machen.
Trotzdem bekommen Sie hinterher ein Modell, das zusammengehört.
Die spielen im selben Spielfeld.
Wenn Sie zwei Sätze haben und in beiden ist der Peter drin, dann
machen Sie keine zwei Peter-Klassen, sondern nur eine.
Ist ja klar, es hat dasselbe Peter oder derselbe Matthias oder was
auch immer.
Die Rollen schauen Sie sich an, gucken Sie nochmal durch, brauchen Sie
auch auf dem Übungsblatt.
Aber es gibt noch andere.
Und was wir gerade eben gesehen haben, war ein Aktus an einem Verb.
Das streicht, das war eine Aktion.
Aber es heißt nicht, dass Sie an jedes Verb einfach Akt dran schreiben
und sagen, das ist eine Aktion.
Sie erinnern sich, es gibt sowas wie wohnt in oder die Geschäftsstelle
liegt in.
Das ist auch ein Verb, aber das ist keine Aktion.
Das ist ein Stat, steht hier zweites von unten, Zustandsverben und
deren Nominalisierung.
Das wären Beziehungen.
Das heißt, wenn Sie einen Satz haben, schauen Sie sich an, was ist die
Semantik von diesem Satz.
Und dann gucken Sie in die Tabelle, was ist die Rolle, mit der ich
diese Semantik auszeichnen kann.
Und dann im nächsten Schritt modellieren Sie es entsprechend von
dieser UML-Umsetzungsspalte, die hier auf der rechten Seite ist.
Das kann man noch ein bisschen komplizierter machen.
Zum Beispiel mit Rollengefügen.
Wir haben jetzt immer nur ein Triple gehabt aus Agens, Patiens und
einer Aktion.
Noch ein Instrument, okay.
Aber man kann sagen, Donor und Habitum, das ist irgendwas, was vorher
noch die Aggregation.
Wir haben hier ein Omnium und ein Pars.
Entschuldigung.
In dem Satz gibt es mehrere Dinge, die interessant sind.
Einmal Peter puzzelt einen Puzzle.
Das heißt, wir haben dieses Puzzeln als Aktion.
Das ist hier auch drin, aber steht halt nicht auf der Folie.
Aber zwischen den Teilen und dem Puzzle besteht natürlich eine Teil
-Ganzes -Beziehung.
Und das sind die zwei Rollen Omnium und Pars.
Und aus diesem Paar, Omnium und Pars, kriegen Sie eine Komposition.
Sie können auch sagen, ich kriege da immer eine Aggregation hin, aber
hier in der Tabelle steht halt Komposition.
Ein anderes Beispiel, das ich eigentlich im Kopf hatte, war Donor und
Rezipient.
Da haben wir jetzt natürlich auch einen Aktus, nämlich das Schenken.
Das ist hier mal ausgeblendet.
Aber Sie sehen, Peter ist derjenige, der was hat und es übergibt.
Und der Frank, der ist derjenige, der es bekommt.
Und dieses Etwas, das ist die Uhr.
Und das können Sie auf verschiedene Arten modellieren.
Sie können natürlich Methoden reinmachen.
Sie können sagen, Peter gibt die Uhr an Frank.
Dann haben Sie das in dieser einen Klasse als Methode lokal gekapselt.
Dafür brauchen Sie vielleicht bei dem Frank auch noch eine Methode,
die das entgegennimmt.
Je nachdem, wie Ihre Modellierung, wie Ihr System aussieht, haben Sie
sogar das Ganze bei der Uhr.
Die Uhr weiß halt, wem sie gehört und die braucht halt zur Prüfung den
Geber und den Empfänger und dann wird es da drin gehandelt.
Könnte auch sein.
Oder wir machen das eher statisch und sagen, es gibt halt eine
Beziehung.
Ich speichere alle Schenkungen.
Könnte auch im juristischen Kontext interessant sein.
Und dann brauche ich eine Beziehung, die das halt einfach darstellt.
Die das speichert und persistiert.
Und dann kriege ich eine dreistellige Beziehung mit diesen drei
Rollen.
Welche dieser beiden Varianten, Klassen und Methoden oder Klasse und
dreistellige Beziehungen Sie bekommen, das ist eine
Entwurfsentscheidung, die Sie treffen müssen.
In der Tabelle steht jetzt beides drin.
Das heißt so viel wie, suchen Sie es sich aus.
Entweder in allen drei Klassen jeweils eine Methode mit den
entsprechenden Argumenten oder die dreistellige Beziehung.
Relativ simpel.
Was ich Ihnen noch zeigen möchte, Crea und Opus gibt es auch noch.
Das heißt, wir haben jemanden, der was erzeugt.
Da entsteht was.
Wenn ich sage, Matthias paints the wall, dann entsteht da nichts.
Dann kriegt die Wand eine andere Farbe.
Aber wenn ich sage, Matthias paints the picture, dann entsteht da ein
Bild.
Das heißt, ich habe zweimal syntaktisch denselben Satz.
Ich habe nur das Objekt ausgetauscht, die Wand gegen das Bild.
Und ich kriege eine andere Bedeutung.
Einmal verfärbt sich die Wand, einmal entsteht ein Bild.
Und je nachdem, was ich ausdrücken möchte, nehme ich andere Rollen.
Ich kann natürlich sagen, malt Bild.
Dann habe ich dieses Crea Opus gemacht, weil hier entsteht.
Da kriege ich ein Bild zurück.
Oder ich entscheide mich für das, der kann nicht malen.
Der macht das mit einer großen Rolle.
Dann habe ich ein blaues Bild.
Dem messe ich keinen künstlerischen Wert zu.
Deswegen ist es nur eine Methode.
Und dann ist das Bild ein Argument.
Genauso wie bei dem Peter Streich, die Wand mit einem Pinsel.
Sie müssen entscheiden, was der Satz bedeutet.
Und dementsprechend müssen Sie die Rollen auswählen.
Sie, die Sie die Rollen dranschreiben, Sie entscheiden, was der Satz
bedeutet.
Wenn Sie der Ansicht sind, ich kann nicht malen, dann nehmen Sie ein
Aktus.
Wenn Sie der Ansicht sind, ich bin ein großer Künstler, dann nehmen
Sie Krea und Opus.
Und dementsprechend machen Sie auch die UML-Umsetzung.
So.
Eine Minute haben wir noch, das reicht.
Diese Rollen werden Sie in der Übung brauchen, weil wir von Ihnen
verlangen, dass Sie an solche Sätze diese thematischen Rollen
dranschreiben.
Aber wir machen das nicht, um Sie zu gängeln, sondern weil das
tatsächlich funktioniert.
Wir haben ein Werkzeug, diesem Werkzeug gibt man einen annotierten
Text.
Das hier ist die Who-Is-Server-Spezifikation oder ein Auszug davon.
Und da geht es um den Verbindungsaufbau.
Der Server hört auf einem Port, nämlich dem 43er, und der Client
schickt eine textuelle Anfrage an den Server und der Server antwortet.
Das ist im Wesentlichen das, was da drin steht.
Und wenn ich da jetzt die thematischen Rollen alle dranschreibe, dann
sieht es ein bisschen wild aus, nämlich so.
Aber Sie sehen ein paar Dinge, die Sie schon mal gesehen haben.
Nämlich, wir haben zum Beispiel einen Agent und einen Stud und einen
Patient.
Das war die Beziehung.
Der Server hat eine Beziehung zu dem Port, die heißt ListenOn.
Wir haben einen Who-Is-Client, der ist der Donor, der gibt was.
Das steht hier auch nochmal.
Nämlich ein Text-Request, das Habitum, und derjenige, der es empfängt,
der Rezipient, das ist der Server.
Da ist nichts anderes gemacht, als den Satz hergenommen, aufgedröselt,
die Bedeutung erfasst und mit den thematischen Rollen hingeschrieben.
Und Sie sehen hier noch so ein paar Dinge wie Kommentarzeichen, das
heißt ignoriertes Wort.
Sie dürfen sich die Kommentarzeichen sparen, die Software braucht es
und es gibt sowas wie Referenzen, also Requests.
Dieser Request hier, das ist derselbe wie hier oben.
Das ist einfach nur die Information für die Software.
Wenn ich diesen Text hernehme, mit den Annotationen in die Software
reinkippe, dann kommt da ein Klassendiagramm raus.
Und das ist deutlich ausgefeilter als Subjekt, Prädikat, Objekt und
mach zwei Klassen und zieh eine Kante dazwischen oder mach eine
Methode.
Sie sehen zum Beispiel, dass dieser Server hier eine Uses-Beziehung
hat und das Listens.
Da haben wir also keine Beziehung, sondern da haben wir eine Methode.
Ich weiß gar nicht, warum das jetzt passiert ist.
Aber das ist das Ergebnis.
Was haben wir noch?
Wir haben den Client hier rechts und den Server hier links.
Und wir haben hier einmal diese Donor-Recipients-Beziehung.
Der Client ist der Donor, nämlich für die Requests.
Und hier unten ist er der Recipients, nämlich für die Response.
Das steht in einem anderen Satz.
Auf diese Weise kann man sehr große und komplexe Dinge einfach
semantisch aufbereiten und sich dann das Klassendiagramm generieren
lassen.
Damit sind wir inhaltlich mit der Vorlesung fertig und die letzte
Folie zeige ich Ihnen nächstes Mal.