Okay, dann herzlich willkommen zur zehnten Vorlesung von SC2.
Ich habe heute mal keine größeren Ansagen.
Heute ist ein ziemlich heißer Tag. Ich bin erfreut,
dass trotzdem noch so viele von euch gekommen sind.
Was ich heute machen will, ist das Thema Klassenentwurf hier mit euch zu besprechen.
Das ist ein relativ abstraktes Thema. In dem Sinne,
dass Entwurfserfahrungen von vielen Leuten kumuliert wurden in bestimmten Regeln,
wie man Systeme zu bauen haben sollte oder nach welchen Regeln es vorteilhaft ist, Systeme zu bauen.
Und das ist allerdings, wenn man diese Regeln abstrakt hernimmt,
dann sind sie relativ hohes Geklingelt. Also hier sind so zwei Begriffe,
Kopplung, Korrision, immer wenn man dann in Prüfungen Leute fragt,
na was sind denn wichtige Begriffe für den Entwurf,
dann kommt sofort Kopplung und Kurse.
Und wenn man dann fragt, was heißt denn überhaupt Kopplung
und Korrision, dann wird es schon ein bisschen schwieriger.
Und ich will heute versuchen, das ein bisschen, sagen wir,
plastischer zu vermitteln, indem ich relativ viel live Code zeige.
Das kennt ihr ja von mir. Und wir werden also versuchen,
diese Konzepte, diese Entwurfskonzepte hier auch nachvollziehbarer zu machen,
anhand von laufenden Systemen. Okay, die übliche Motivation,
warum man sich mit dem Thema Klassenentwurf beschäftigen sollte.
Also warum ist es denn wichtig, wie man seine Softwaresysteme entwirft?
Nicht nur im Sinne von dem, was sie nach außen liefern sollen,
also was ein Benutzer der Software zu sehen bekommt,
das ist die äußere Qualität, sondern es ist eben halt auch wichtig,
die intern oder innere Qualität zu berücksichtigen.
Und das heißt, Verständlichkeit, also jemand muss sich in ein System,
das ihr gebaut habt, einlesen, dann ist es gut,
wenn es irgendwie nach relativ bekannten Regeln gebaut ist.
Was wir euch hier bisher so vermittelt haben, waren ja
sehr konkrete Entwurfsregeln für SE2. Da habe ich schon versucht,
deutlich zu machen, dass die Entwurfsregeln sehr spezifisch sind.
Und jedem Projekt kann man wieder andere nehmen. Sie sind aber,
das ist eine ganz interessante Ausprägung, von denen allgemeineren Regeln,
die heute drankommen. Also das sind sozusagen,
ich will nicht sagen ultimative Wahrheiten, die ich jetzt verkünde,
das wäre ein bisschen großes Wort,
aber das sind schon, sagen wir, Entwurfsrichtlinien,
die deutlich mehr Wirkungsgrad haben als das,
was wir jetzt euch hier für SE2 an Entwurfsregeln mitgegeben haben
Ja, man muss ja nicht alles so strukturieren,
dass man es mit Werkzeugen und Materialien baut, aber das,
was jetzt hier heute drankommt, schon. Und Verständlichkeit,
wie gesagt, schon bei den Entwurfsregeln für SC2 war es so,
dass wir gesagt haben, wenn jemand anderes die Entwurfsregeln kennt,
sich ein System anguckt,
kann er sich so total schnell einlesen in so ein System.
Also wenn ihr jetzt zwei Systeme gesehen habt,
die Mediathek und das Kinoticket-Verkaufssystem und ihr kriegt ein drittes System,
das nach diesen Entwurfsregeln gebaut ist, würde ich vermuten oder hoffen,
dass ihr euch relativ leicht einlesen könnt und relativ leicht erkennen könnt,
wo ihr etwas dazu bauen müsst, wenn etwas dazu gebaut werden muss.
Das geht dann auch in Richtung Wattbarkeit und natürlich auch in
die Richtung von Modularität.
Also wie zerteile ich denn ein großes System in kleinere,
handhabbarere Teile
Klar ist, die äußere Qualität ist wichtiger,
weil das ist das, was die Software letztendlich abliefert nach außen.
Aber das habe ich auch schon versucht, mehrfach anzudeuten,
auf Dauer wird sich mit einem fürchterlichen Klassenentwurf auch eine gute Software nicht halten können,
wenn sie über mehrere Jahre weiterentwickelt werden sollen.
Okay, bevor wir da jetzt ein bisschen reinsteigen in
dieses Thema und in diese Entwurfsregeln oder Entwurfsregeln, Entwurfsrichtlinien,
würde ich gerne nochmal den Begriff Entwurf etwas differenzieren.
Also wenn wir hier über Entwurfsregeln sprechen, was heißt denn
überhaupt Entwurf? Und man kann da eben differenzieren,
zum einen kann man sagen, Das System hat einen Entwurf,
das ist eine Eigenschaft eines bereits existierenden Systems.
Also da ist eine Struktur zu erkennen.
Und da kann ich jetzt sagen, ja,
das sieht mir aus, das ist ganz gut entworfen.
Es könnte auch sein, das ist die Architektur.
Also der Entwurf dieses Systems ist ungefähr so das Gleiche wie die Architektur des Systems.
Das heißt, wir werden ja auch so Begriffe wie Softwarearchitektur
immer wieder zu hören bekommen, auch später bei Softwareentwicklung.
Und dann sind eben so Fragen wie,
welche Elemente existieren denn in dem Softwaresystem,
wie arbeiten die zusammen und so weiter
Man kann aber auch sagen, Entwurf ist eine Tätigkeit.
Etwas wie ich bin jetzt mit mehreren Leuten dabei,
ein System zu bauen und ja, beim Klassenentwurf haben wir festgestellt,
dass die Aufteilung nicht so ganz einfach ist.
Natürlich auch bei euren Entwürfen, die ihr gemacht habt,
also bei euren Entwurfstätigkeiten, habt ihr gemerkt,
die Sache mit dem Vormerken in der Mediathek,
wo gehört ihr eigentlich genau hin?
Ist nicht so ganz einfach. Das heißt,
da geht es dann vor allen Dingen um Entscheidungen treffen.
Das andere ist so, da ist eine Struktur und die
kann man vielleicht bewerten, ausmessen.
Und beim Entwerfen geht es aber tatsächlich um Entscheidungen
Das ist ganz wichtig, wenn ihr Systeme baut,
dann gibt es fast nie die Schwarz-Weiß-Lösung,
sondern es ist immer so, ja,
man kann das so oder so machen und das hat alles Vor- und Nachteile.
Es wird also immer stärker ein Entwurfsraum, in dem ihr
euch bewegt und da gibt es eben halt dann Vor- und Nachteile,
die man abwägen muss. Wenn ihr dann so Entscheidungen trefft,
müsst ihr euch auch überlegen, wann ihr welche Entscheidungen trefft,
aber man kann nicht alle Entscheidungen für ein System am ersten Tag treffen,
sondern das ist irgendwie so ein Prozess,
der oft über Monate geht,
also braucht man auch irgendwo so eine Art Planungskomponente,
wenn man den Entwurf als Tätigkeit ansieht
Eine Möglichkeit, Unterstützung beim Entwerfen sind CAC-Karten. CAC-Karten sind ein Konzept,
das früher in der Vorlesung von Heinz über wann mit drin war.
Das passte da nicht so richtig gut dazu. Deswegen habe ich
es jetzt hier ein bisschen mit dazugenommen. Das heißt also,
die beiden Folien, die ich als nächstes zeige,
sind nicht im Skript, also nicht erschrecken.
Und wenn ich die kurz vorgestellt habe,
dann können wir uns um das Thema Klassenentwurf kümmern im Sinne von,
woher wissen wir denn, dass ein Entwurf gut ist im ersten Sinne von Architektur.
CAC-Karten sind ein relativ simples Konzept. Es ist einfach die Idee,
dass man verschiedene Aspekte in einem objektnotierten System unterscheiden kann,
nämlich zum einen die Klassen, dann die Zuständigkeiten,
die eine Klasse hat, also was sie denn tun soll und mit welchen anderen Klassen sie zusammenarbeitet.
Also die Klasse, Klaas, C-Zuständigkeiten, Responsibility und Zusammenarbeit Collaboration, deswegen CRC.
Das ist erstmal diese Begriffszusammensetzung. Das Akronym ist also,
setzt sich so zusammen. Wenn man dazu diesen Artikel liest,
und das würde ich jedem von euch empfehlen,
der sich einigermaßen für dieses Thema interessiert,
Ein relativ kurzer Artikel sind nur sechs Seiten,
sehr gut lesbar, ein echter Klassiker.
Da haben Can't Back und Walt Canningham dargestellt,
wie man denn CRC-Karten einsetzen kann, also CRC,
diese Begriffe unterscheiden und das mit Karten tatsächlich so einfach ein Karteikarten,
um Entwürfe zu machen.
Und kann man sich so vorstellen,
so diese drei Begriffe sind dann auch diesen drei Abschnitten,
also oben steht der Klassenname und dann hier links üblicherweise im unteren Bereich die Zuständigkeiten,
unter rechts die Zusammenarbeit mit anderen Dienstleistern.
Also welche anderen Klassen hat man da im Spiel
So, und dann ist es hier schon irgendwie erkennbar,
das sind jetzt nicht unbedingt Methoden, die man da definiert.
Es ist noch gar nicht programmiertechnisch,
sondern wenn ich in einem Anwendungsbereich versuche, mir zu erschließen,
wie die Dinge zusammenhängen, dann kann ich sagen,
naja, da gibt es Girokonten, da gibt es Verträge,
sondern dann versuche ich die erstmal auf eine Karte zu schreiben,
diese Begriffe.
Und dann versuche ich mir zu überlegen, wer ist denn für was zuständig?
Also was bietet denn so ein Girokonto, was hat so
ein Konto, so ein Vertrag für Eigenschaften und so weiter?
Und dann formuliert man die erstmal und stellt dann fest,
naja, dafür muss man natürlich bestimmte Informationen bekommen von jemand anders,
also wenn hier beim Konto zum Beispiel, sowas gibt wie einen Betrag einzeln,
dann wird man wahrscheinlich so was haben wie eine Klasse Betrag oder einen Typbetrag.
Man sieht an dieser Stelle auch jetzt schon so eine Vermischung von Konzepten,
die ich gleich noch thematisieren will,
dass also hier der Betrag etwas ist, was ziemlich klar zur Schnittstelle gehört.
Also wenn ich hier an einem Girokonto einen Betrag einzahlen würde und mir vorstelle,
dann werden jetzt irgendwann Methoden definiert,
die dann einen Parameter als Betrag, einen Betrag als Parameter bekommen,
dann musste es sowieso sowas wie einen Betrag geben für einen Klienten.
Andererseits ist hier aber jetzt auch Liste um die Kontobewegung
zu verwalten, ist jetzt wahrscheinlich ein bisschen konstruiert hier.
Das ist eher so ein Detail der Implementation und wir wollen
ja auch unterscheiden zwischen Schnittstellen und Implementation
Aber ihr seht,
man kann da eben halt so mit diesen Karten sehr schönes Brainstorming machen,
kann sich wirklich mit mehreren Leuten am Tisch hinsetzen,
kann diese Karten ausfüllen, beschriften, was durchstreichen,
was bewegen zwischen den Karten und so weiter.
Und dann mithilfe von diesen Karten auch quasi das durchspielen.
Also eine sehr hilfreiche Methode. Wie gesagt, lest diesen Artikel,
dann versteht ihr mehr darüber, sehr, sehr pragmatisch.
Also kein theoretisches Konzept, sondern extrem nützlich und pragmatisch.
Sowohl um sich ein Anwendungsbereich so ein bisschen begrifflich zu erschließen,
als auch um konkrete Entwürfe von Systemen
zu bauen
Gut, also jetzt die eigentliche Frage. Wie kommen wir
zu einem guten Entwurf? Und da will ich halt hier
ein paar Richtlinien jetzt vorstellen. Allgemein gilt,
so als Grundregel, dass wir nach Zuständigkeiten entwerfen wollen,
werde ich gleich mehr zu sagen.
Und dann gibt es zwei große Themenbereiche, nämlich einmal Kopplung,
einmal Korrision, und zwar lose Kopplung.
Da gibt es dann verschiedene Untermaßnahmen, die man da mal
ergreifen kann, um lose Kopplung zu erreichen.
Und wie erreicht man eine hohe Korrision?
Auch da gibt es
verschiedene Maßnahmen
Die gehen wir jetzt durch. Das ist sozusagen die Übersicht
über das, was ich heute hier erzählen will.
Und ja, wir fangen an mit diesem Leitbildentwurf nach Zuständigkeiten.
Im Englischen heißt das Responsibility Driven Design.
Ist eine Entwurfsphilosophie, die es schon ziemlich lange gibt,
also seit den frühen Tagen der Objektorientierung.
Rebecca West Brock hat den maßgeblich mitgeprägt, aber auch,
wie gesagt, Cant Back.
Das war so die gleiche Zeit, Ende der 80er.
Und die Idee ist, eigentlich ganz einfach,
Objects I not just simple bundles of largic and data,
they responsible members
of in object community
Das ist etwas, was für euch hier jetzt,
wo ihr SE1 besucht habt und auch SE2 gemacht habt,
wahrscheinlich nicht mehr ganz so absurd,
aber es gab eben Zeiten, da war das anders.
Da gab es die Imperative Programmierung, die sagte,
Programmierung ist eigentlich Daten und Algorithmen auf den Daten.
So, das ist die klassische Sicht.
Der hat einen getrennt von den Algorithmen. Die Objektorientierung hat
das irgendwie anders zusammengebracht. Und da hat er gesagt,
naja, eigentlich haben wir so eine Gemeinschaft von Objekten,
die irgendwie miteinander kollaborieren, zusammenarbeiten.
Und eben halt nicht einfach nur zusammengeklebt, so Logik und Daten,
sondern da steckt irgendwie eine Überlegung dahinter,
wer oder welches Objekt ist für welche Rolle in dem System
Und das ist die Grundidee von Objekt notiertem Entwurf.
Und die leitet eigentlich alles, was jetzt hier auch dann nachfolgend ich vorstelle.
Ist auch nicht wirklich was Neues im Sinne von Zuständigkeiten
feststellen und dann auch Concerns zu trennen.
Das hat auch schon der gute Deiks drauf vorgeschlagen, allerdings weniger objektorientiert.
Aber das ist natürlich eine Grundregel, die man immer hat.
Teile und Herrsche, also versuche die Dinge zu trennen,
wunderbar. Aber das ganze Objektorientiert zu machen,
ist eben halt nochmal
einen Schritt weiter
Okay, ich hatte gesagt, ich will das ein bisschen konkret machen.
Ich mache es ein bisschen konkret. Ich habe hier
Blue Jay dabei. Und ich habe hier ein Projekt,
das ihr kennen könnt, aber nicht kennen müsst.
Nämlich das Projekt Grafen, das ist Blatt 14 aus SE1. Blatt 14
hat wahrscheinlich keiner von euch bearbeitet, vielleicht manche schon.
Ich vermute eher nicht. Habe ich auch in der Vorlesung,
vor diesem 14 kurz vorgestellt, sieht eigentlich ganz einfach aus.
Man sieht hier, es gibt irgendwas mit einem Hauptfenster,
also irgendwie eine grafische Oberfläche. Ich kann das hier mal
starten. Dann sieht man auch, was da passiert.
Da wird also tatsächlich hier ein Graf angezeigt und ich kann mit
dieser interaktiven Oberfläche jetzt hier so diese Knoten so ein bisschen hin und her bewegen.
Das ist eigentlich eher so ein bisschen nur, damit es
ein bisschen sexy aussieht, dann kann man hier neue Knoten erzeugen.
Ja, und dann kann man hier irgendwie Knoten auch verbinden miteinander.
Ich kann also jetzt hier sagen, Kantengewicht 34,
neue Verbindung zwischen diesem und diesem. So,
und dann haben die halt eine Verbindung von 34. Das heißt,
diese Verbindung hat ein Gewicht, das heißt,
das ist ein gewichteter Graf.
Wir können uns also vorstellen, dass den abstrakt Städte,
Flugverbindung und dann sieht man irgendwie die Kosten,
die für so eine Flugverbindung notwendig ist
Oder es sind Entfernungskosten für ein Navigationssystem, wie auch immer.
Könnt ihr euch sicherlich einiges darunter vorstellen. Es ist auch
nicht gerichtet, dieser Graf. Das sind also hier keine
Pfeilspitzen an den Verbindungen. Und ja, wir haben also
eine Menge von Knoten und wir haben eine Menge von Kanten.
Soweit so gut. Diesen Graf kann man hier manipulieren und dann sollte man in diesem Projekt,
was wir euch damals gegeben haben, so Fragen beantworten,
wie, wenn ich jetzt auf diesen Knoten klicke und auf diesen Knoten klicke,
sind zwei Knoten selektiert,
der hier und der hier so,
jetzt sind
die wirklich selektiert
Programmatisch zu bestimmen, ob die verbunden sind.
Das sieht man in diesem Graf jetzt mit Hingucken relativ leicht,
aber bei größeren Grafen wisst ihr, das ist nicht so einfach.
Und dann so Dinge wie, was ist der kürzeste Weg
und so weiter. Das war, wie gesagt,
das war so das Projekt, das wir euch gegeben haben.
Warum ich das jetzt hier vorne habe, ist,
ich möchte erstens zeigen, dass das aus hier zwei Klassen besteht,
die pure Fachlichkeit modellieren.
Das heißt, es geht in diesem Projekt um Grafen
und um Algorithmen auf Grafen.
So, ihr habt in diskreter Mathematik wahrscheinlich das
auch das Thema gehabt,
Algorithmen auf Grafen
Das ist also die mathematische Fachlichkeit. Und jetzt ist die
Frage, wie ist das hier abgebildet in einem Software-System?
Da kann man jemand sagen, naja, hier ist es halt objektorientiert modelliert.
Ein Graf benutzt Knoten, also ein Graf ist eine Menge von Knoten.
Und das ist in diesem System so modelliert, dass ein Knoten
einen Nachbar haben kann. Ich habe also hier verbinde mit,
kann also einen Knoten eintragen mit einem Kantengewicht.
Und dann kann ich die Verbindung auch trennen. Ich kann mir fragen,
ob ein Knoten zu einem anderen Knoten eine Verbindung hat.
Und ich kann mir das Verbindungsgewicht geben lassen zu einem anderen Knoten.
Relativ einfach. Das heißt, die Verbindung zwischen den Knoten
sind modelliert als Referenzen auf andere Knoten
Ist halt so objektorientiert in Java ganz gut möglich.
Und ein Graf, das ist dann das, was hier
so dazugehört, das ist richtig eine Menge von Knoten.
Das ist die Knotenmenge hier. So ein Graf setzt sich
aus einer Knotenmenge zusammen. Und dann gibt es hier die Möglichkeit,
den Graf neun Knoten hinzuzufügen. Das ist das,
was dann tatsächlich von der Gui gerade aufgerufen wurde.
Als ich hier auf neue Knoten geklickt habe in der Oberfläche,
hier neuer Knoten, dann wurde hier aufgerufen,
neuer Knoten und dann wurde der halt entsprechend hinzugefügt
Okay, und man kann dann hier auch die Knoten miteinander verbinden.
Man kann fragen, ob ein Knoten enthalten ist.
Die Anzahl der Knoten kann man sich geben lassen,
ist also relativ einfach zu beantworten.
Die intern verwendete Menge wird einfach size aufgerufen.
Man kann iterieren über alle Knoten des Graphen. Das ist
dieses Iterator-Interface hier, das sieht man auch da oben nochmal.
Ich stehe kurz hoch. Graph-Implements, Iterible-Knoten. Also man
kann sozusagen über die Knotenmenge eines Graphen iterieren. Ja,
und dann haben wir hier so ein paar Sachen offen gelassen.
Also zum Beispiel die Frage sind zwei Knoten verbunden,
werden zwei Knoten übergeben.
Und man soll jetzt hier sagen,
ob die verbunden sind oder nicht
Solange die beiden Knoten verschieden sind und beide auch zum Graf
gehören, kann dann diese Frage beantwortet werden.
So, dann die Anzahl der Komponenten,
also aus wie vielen verschiedenen nicht zusammenhängenden Komponenten besteht der Graf.
Und hier unter anderem auch der Grad. So,
der Grad eines Knoten, wer weiß,
was der Grad eines, der Grad eines Grafen ist.
So, mal eben ganz kurz so die diskrete Mathematik rausgeholt.
Ach so, steht da schon. Na gut,
lief für den Grad dieses Grafen an den maximalen Grad seiner Knoten.
Gut, es steht da schon. Schade,
aber darum geht es ja auch gar nicht.
Also ein Knoten in einem Grafen hat einen Grad.
Das ist einfach die Anzahl seiner Nachbarn.
Also die Anzahl der Knoten, mit denen er verbunden ist
Ich mir diesen Grafen angucke, dann hat dieser Knoten hier
zwei Nachbarn, also es ist ein Grad 2.
Dieser Knoten hat hier sechs Nachbarn, also es ist ein Grad sechs.
Okay, und jetzt möchte ich hier diese Operation Grad implementieren.
Ich möchte also den Grad für den Graf ermitteln.
Hat jemand eine Idee, wie man das jetzt mal implementieren könnte?
Also so ganz schnell, ja. Okay,
er sagt einfach durch die Menge der Knoten durchgehen und sich
den höchsten Wert speichern, also den höchsten Grad speichern.
Okay, gut, dann machen wir das nochmal,
dann sage ich hier irgendwie in Max Grad
Ist mal zu Anfang gleich null. Und am Ende sage ich hier,
Return Max Grad, will also jetzt irgendwie Code schreiben,
der den Grad ermittelt, dann schreibe ich hier eine Vorschleife,
also vor Knoten K in der Knotenmenge dieses Graphen.
So, und jetzt gehe ich also durch alle Knoten
durch und was muss ich jetzt als nächstes tun?
Ja. Graph ist eins
Genau, also ich muss jetzt für jeden einzelnen Knoten fragen,
ob sein Grad höher ist, als der bisher gemerkte Max-Grad.
Gut, dann machen wir das doch mal. Dann habe ich
hier irgendwie ein Int-Grad, ist gleich null. So,
und jetzt habe ich hier die Möglichkeit in diesem System,
war über einen Knoten zu iterieren.
Ich kann tatsächlich auch hier bei einem Knoten wieder sagen,
also der Knoten implementiert auch Eterible.
Das heißt, ich kann bei einem Knoten über seine Nachbarn iterieren.
Also so ähnlich wie bei dem Grafen kann ich ja über alle,
kann ich auch bei einem einzelnen Knoten jetzt über seine Nachbarn
Kann man nur Knoten in ein paar Fragen,
wenn ich werde, also die Leute in die Klasse.
Okay, er sagt, kann man den Knoten nicht einfach fragen,
welchen Grad er hat? Okay, ich gucke mal,
ob der Knoten eine Operation hat, welchen Grad er hat.
Der hat keine Operation, die seinen Grad liefert.
Okay, das heißt, ich mache jetzt mal was,
ich baue jetzt hier mal was und dann will ich ja hinterher darüber diskutieren.
Ich mache also hier eine weitere Vorschleife, nämlich für alle Knoten,
Nachbarn, für alle Nachbarn von dem Knoten K,
sage ich jetzt einfach, Mache ich jetzt hier einfach Grad.
Ist gleich Grad plus eins. So. Und wenn ich das jetzt mache,
dann habe ich hinterher den Grad des Knoten und dann kann ich
hinterher auch wirklich fragen, ist dieser Grad größer als?
Also If Grad größer Max Grad, dann können wir relativ leicht implementieren,
dass Max Grad dann neu gesetzt wird,
nämlich mit dem Wert von Grad.
So, lasst dich übersetzen
Liefert hoffentlich den Max Grad. Ist das erstmal für alle nachvollziehbar,
was ich hier im Implementiert habe? Scheint einfach zu sein
. Gut. Wunderbar. Wir probieren das mal aus.
Ich übersetze das mal. Rufe mal hier wieder mein Main auf.
Dann wird hier wieder dieser Graf angezeigt. Und jetzt kann ich,
das ist so ein bisschen bei diesem System so gewesen,
kann ich mir den Grafen,
der jetzt hier gerade angezeigt wird, geben lassen.
Ich kann also wirklich hier sagen, gib mir doch mal den visualisierten Graf.
Dann habe ich mir die Referenz hier auf die Leiste liegen.
Habe also jetzt eine Referenz auf genau diesen Graf.
So, und dann würde ich jetzt erwarten,
wenn ich jetzt den Grad abfrage, dass da sechs rauskommt.
Und es kommt sechs raus, herrlich,
weil der Knoten mit den meisten Nachbarn ist ja der,
Hier in der Mitte, der hat sechs Nachbarn.
Gut, ich kann jetzt nochmal eben viel eine Verbindung einzeigen,
dass wir das nochmal seht.
Neue Verbindung, damit ihr auch wirklich mir traut,
dass das hier im Moment neue Verbindungen, Zielknoten wählen.
So, jetzt müsst ihr hoffentlich sieben rauskommen,
gucken wir mal. Grad sieben, toll. Gut.
Was wir gerade gesehen haben, war eine korrekte Implementation.
Sie macht das Richtige. Sie macht das Richtige.
Was ist das Problem? Was könnte das Problem sein
an dieser Stelle
Also wir vermitteln sich an, so organisiert wirst.
Aber das ist alles mit dem Nachbarn. Okay,
also er sagt, das ist jetzt ein bisschen doof,
dass der Graf wissen muss, wie der Knoten intern aufgebaut ist.
Man muss es ja eigentlich keine Eigenschaft, das ist keine Implementationseigenschaft,
sondern das steht ja an der Schnittstelle,
dass man über die Nachbarn eines Knoten iterieren kann.
Das ist eigentlich mindestens eventuell eine Einladung für mich,
für den Knoten, eben sein Gerade auszufinden,
aber das kann der Graf nicht wir sind,
weil das ja ein Geheimnis positive Toten beworben ist.
Das heißt, ein Knoten zur Frage, den ich gerade hat,
er würde zumindest schon mal eine Möglichkeit wie geführt Internationsbank hier im Mittelbildgrad, mit Knotenkrapseln.
Okay, also was er gesagt hat, ist,
irgendwo ist es jetzt so ein bisschen das Geheimnis des Knotens,
wie viele Nachbarn er hat.
Man muss ihn sozusagen erst danach fragen.
Das ist genau der entscheidende Punkt. Dieser Code hier,
also das, was hier steht, das hier,
ist nur ein kleines Stück Code, ganz unschuldig.
Aber das steht jetzt hier im Graphen,
um von einem Knoten zu ermitteln, welchen Grad er hat.
Und der Vorschlag war ja schon von Anfang an,
eigentlich sollte der Knoten eine Methode haben, die den Grat liefert.
Warum ist das sinnvoll, das im Knoten steht,
naja, weil möglicherweise noch andere Algorithmen existieren,
möglicherweise noch weitere Klassen, die auf diesen Knoten arbeiten.
Und wenn die dann auch schön ihre kleine Vorschleife schreiben,
um über diese Knotenmenge zu iterieren,
dann haben wir diesen Code an mehreren Stellen im System.
Und das ist relativ hässlich. Und tatsächlich ist es
ein Beispiel jetzt für den Entwurf nach Zuständigkeiten,
wer ist denn dafür zuständig, den Grad eines Knotens zu ermitteln?
Naja, eben genau nicht der Graf,
sondern der Knoten ist dafür zuständig,
seinen Grad zu kennen und ihn vielleicht auch als angenehme Methode
direkt anzubieten
Man kann das, wie gesagt, so iterieren machen,
aber ja, es wäre deutlich schöner,
wenn da Stünde verknoten, in Knotenmenge, ifknoten.grad,
größer Max Grad, dann Max Grad gleich, knoten.grad.
Wenn der Knoten das liefern würde, wäre deutlich,
wäre hier knapper und die Zuständigkeit zum Ermitteln des Grads wäre tatsächlich richtig zugeordnet.
Das ist ein Beispiel für den Entwurf nach Zuständigkeiten.
Oh sorry, ich bin hier so ein bisschen an
meine Güte, suchen nach meinen Folien.
Also jedes Objekt sollte für ein eigenes Dings zuständig sein
Ich habe ein weiteres Beispiel. Wir werden das
gleich noch mal ein bisschen hier uns genauer angucken.
Ich werde das mal wieder mal vorne und nach vorne holen.
Dies zum Beispiel. Das andere Beispiel, das ihr auch kennt
, ist die Mediathek. Hier ist das Eclipse-System dazu.
Hier ist unsere, in Anführungsstrichen, Musterlösung.
Wenn ich jetzt hier das System starte,
dann habe ich hier in der Vormerkansicht die Möglichkeit ja implementieren sollen,
solltet ihr implementieren, dass man vormerken kann.
Das heißt, man sieht hier diese Möglichkeit zum Vormerken
ist momentan nicht da, weil der Vormerk-Button ist ausgegraut.
So, jetzt soll entschieden werden, dass jemand vormerken kann
Die Frage ist, wer ist dafür zuständig, diese Frage zu beantworten?
Also das ist hier implementiert gewesen, schon in der Gui für euch
vorgegeben, mit einer Methode ist Vormerken möglich. Okay,
also das heißt irgendwie, dieser Button sollte nur aktiviert werden,
wenn hier jemand selektiert ist, also hier musst du ein
Kunde selektiert sein und hier muss irgendwie auch ein Medium mindestens ein selektiert sein,
dann kann möglicherweise vorgemerkt werden.
So, und die Frage ist jetzt,
an welcher Stelle ist das jetzt implementiert?
Dieses ist Vormerken möglich
Und da haben wir in den Übungen verschiedene Entwürfe gesehen.
Da haben einige dann eine Vormerkkarte gebaut und die Vormerkkarte hatte
eine Q intern. Und dann war das ähnlich,
wie du das gerade hast, was wir gerade gesehen haben.
Habe ich oft Code gesehen, der dann sich von der Vormerkkarte
die Q hat geben lassen und selber durch die Q durchgehühnert ist.
Statt die Vormerkkarte zu fragen, sag mal,
hast du noch Platz für einen Vormerker?
Aber die Vormerkkarte kann das natürlich nicht alleine beantworten.
Das war auch ein Problemeintwurf für viele von euch,
dass man auf der Vormerkkarte ja gar nicht weiß,
ob der schon, das Ding ausgeliehen hat.
Also wir haben ja hier die Situation,
wenn zum Beispiel ich jetzt hier Kai Konrad auswähle,
dann kann der das hier nicht vormerken, weil das ja schon ausgeliehen hat.
Das kann die Vormerkkarte, also so eine kleine dumme Karte,
aber gar nicht genau wissen. Sie ist ja nicht dafür zuständig,
auch zu wissen, wer das Ding ausgeliehen hat. Das heißt also,
ein Teil der Zuständigkeit für die Beantwortung dieser Frage steckt in der Vormerkkarte,
ein Teil in dem Verleihservice und ein Teil in der Gui,
weil in der Gui ja auch erstmal überhaupt hier ein Element selektiert sein muss,
solange hier kein Element selektiert ist,
stellt sich diese Frage gar nicht.
Also hier muss also auch erstmal geprüft werden,
dass überhaupt ein Vormerken möglich abgefragt werden kann.
Und das ist eben genau das, was Hier so ein bisschen
auch ich auf der Folie angedeutet habe. Diese Information,
wer dafür zuständig ist, das ist natürlich erst mal was,
dass das Vormerkwerkzeug, das muss es irgendwie rausbekommen,
fragt beim Verleihservice nach und der Verleihservice weiß dann,
welche anhand der Verleihkarten, wer der Verleiher ist,
kann also diese Frage, diese Teilfrage beantworten.
Ist das Ding vielleicht schon an den Vormerker verliehen?
An den potenziellen Formerker. Und die Vormerkkarte kann aber immerhin beantworten,
wenn man ihr einen Kunden reinreicht, dann kann die Vormerkkarte sagen,
Erstens kann ich prüfen, ob ich überhaupt Platz habe.
Vielleicht ist die Karte ja schon voll. Es sind schon
drei Positionen besetzt. Und wenn nicht, kann man,
wenn da noch Platz ist, kann es trotzdem sein,
dass die Kunde dir da übergeben wird,
schon auf der Karte eingetragen ist.
Das kann diese Formel-Karte für sich entscheiden. Das heißt,
an der Schnittstelle der Formel-Karte kann das wirklich beantwortet werden.
Also auch da kann, und das ist eben halt,
es ist nicht immer ganz einfach in einem Objekt und in diesem System,
die Zuständigkeit für eine bestimmte Aufgabe komplett an eine Stelle zu stecken.
Das wäre ja schön,
aber man muss eben halt eigentlich immer fragen,
wer kann denn
was oder welchen Teil der Frage beantworten
Und hier sieht man ihm halt deutlich,
bestimmte Teilfragen lassen sich gut von einer Vormerkkarte beantworten.
Und sollten nicht irgendwie so an die Kunden delegiert werden.
Das gucken wir uns gleich auch nochmal an, wie das dann schiefgehen kann.
Gut. Dann hatte ich schon vor ein paar Wochen mal gesagt,
es ist schlau, wenn man objektive Systeme baut.
Fachlogik und Technik zu trennen. Also fachliche Klassen zu haben
und technische Klassen. Die fachlichen Klassen zum Beispiel in
diesem System hier, in diesem Blue Jay-System,
sind Graf und Knoten
Das sind die Klassen, die tatsächlich die eigentliche Fachlichkeit,
die modelliert werden soll, nämlich Grafen, abbildet.
Auf eine bestimmte objektentierte Art und Weise.
Es gibt tausend Möglichkeiten, Grafen zu modellieren in Software.
Das ist eben halt eine objektorientierte. Und dann ist es aber auch so,
dass hier das Hauptfenster dafür zuständig ist, das ganze Zeug zu visualisieren.
Das System, was ihr damals hattet, sah ein bisschen
anders aus. Das hatte eine Das sah so aus.
Da waren also ein paar Mehrklassen dabei. Das heißt,
hier gab es dann so ein paar Klassen,
die eigentlich nur dafür zuständig waren, das Ganze zu visualisieren.
Das habe ich jetzt einfach mal ausgeblendet,
weil eigentlich man jetzt aus Sicht des Klienten,
also jetzt interaktiver Klient, ich,
ich will jetzt eigentlich hier das gar nicht sehen,
blende hier was aus.
Übrigens nicht wundern, diese Funktionalität, dass ich hier so
sozusagen Klassen aus dem Klassendiagramm ausblenden kann, die kennt ihr nicht.
Die gibt es in Blue Jay bisher noch nicht.
Das ist jetzt ein von uns entwickeltes Plugin, dass genau
die Unterscheidung von Schnittstelle und Implementation auch im Klassendiagramm ermöglicht.
Das heißt also, dass diese Klasse jetzt intern andere Klassen verwendet,
ist ein Detail ihrer Implementation. Ihr könnt euch das so vorstellen,
das Ding ist jetzt zugeklappt und man sieht nur die Schnittstelle,
die man als Klient sein muss.
Ich kann also tatsächlich jetzt hier aufrufen,
Main oder gib mir mal den visualisierten Graphen.
Das ist das, was ich interaktiv machen will.
Wie es gebaut ist, ist mir erstmal egal.
Kann aber das Ding aufklappen und dann sehe ich halt,
aha, oh, da sind noch mehr Klassen dahinter.
Was man aber sieht ist, hier ist eine relativ klare Trennung.
Hier, Fachlichkeit, hier Technik, um das Ding zu visualisieren.
Okay, das ist also so ein Beispiel von dieser Trennung.
So, und jetzt kommen wir genau zu einem zentralen Begriff,
nämlich Den Begriff Kopplung.
Und das ist jetzt hier die objektorientierte Ausprägung dieses Begriffs.
Der hat eine gewisse Geschichte auch in der Informatik,
die wir hier jetzt nicht weiter reflektieren wollen.
Einfach jetzt für das, was ich hier vermitteln will,
ist, Kopplung bezeichnet den Grad der Abhängigkeiten zwischen den Einheiten eines Softwaresystems.
Hier scheint irgendwie ein Leerzeichen zu fehlen. Okay,
also einfach den Grad der Abhängigkeiten zwischen den Einheiten.
Und Abhängigkeiten wisst ihr aus den Klassendiagrammen zum Beispiel,
der UML. Da gibt es Benutzbeziehungen oder gibt es Vererbungsbeziehungen
So, und dann, das sind eigentlich Verbindungen in so einem Grafen.
Und je mehr Verbindungen ich habe, desto mehr Kopplung habe ich.
Und diese Einheiten zwischen denen gekoppelt wird, können Klassen sein,
Pakete, Subsysteme, aber auch Methoden.
So, und hier ist mal so ein bisschen angedeutet,
wie man sich Kopplungen visualisieren kann. Also hier ist ein
Beispiel mit irgendwie sechs Klassen oder sechs Objekten, sechs Einheiten.
Und jede Einheit ist mit jeder anderen gekoppelt.
Also irgendwo kennen die sich alle gegenseitig. Das ist der
maximale Grad an Kopplung, den man sich denken kann.
Jeder kennt jeden
Das ist eigentlich im sozialen Sinne sehr schön,
wenn jeder jeden kennt, für den objektnotierten Entwurf ist es ziemlich unglücklich,
weil es mir jetzt Schwierigkeiten bereitet,
mich irgendwo in diesen Entwurf einzulesen.
Also wo geht es denn los? Was ist denn der
Einstieg? Was ist denn wichtig? Was ist weniger wichtig
? Alles ein flaches Geflecht und jeder kennt jeden.
Ich weiß gar nicht so genau, wo ich anfangen soll.
So ein Entwurf hier sieht dann ein bisschen anders aus.
Hier hat man offensichtlich mehrere Elemente und dieses eine Element in der Mitte
kennt alle anderen oder die kennen auch den in der Mitte,
aber ansonsten kennen die sich außen erstmal nicht
Das ist letztendlich die Visualisierung eines Entwurfsmusters, nämlich des Mediators, Vermittler.
Also diese Klasse, dieses Objekt vermittelt zwischen den anderen Elementen.
Das ist deutlich aufgeräumter. Da ist es möglicherweise relativ einfach zu sehen,
aha, irgendwo scheint das so eine Schaltstelle zu sein,
dann gucke ich mir die erst mal an.
Also je mehr Abhängigkeiten in einem System existieren,
desto stärker ist die Kopplung und was wir wollen,
ist möglichst lose Kopplung.
Also möglichst geringe Kopplung, möglichst wenig Verbindung,
so wenig wie möglich, reduzieren,
weniger,
so wie mit den Steuern
Und die lose Kopplung ist deshalb erstrebenswert,
weil wir erstens eine einzelne Klasse besser verstehen können,
wenn wir uns nicht andere Klassen angucken müssen, um sie zu verstehen.
Also wenn ich mir so einen Baum vorstelle,
für so einen Beziehungsbaum, so zwischen den Knoten,
und dann gibt es Blätter, dann ist es wahrscheinlich so,
dass ich mich in diese Blätter leichter einlesen kann.
Weil diese Blätter benutzen keine Adern Klassen, die kann sie
sozusagen in sich selbst verstehen. Die haben also eine Schnittstelle,
die sie anbieten, aber ich kann die aus sich selbst verstehen.
Das heißt, ich habe eine Möglichkeit sozusagen von den einfacheren Klassen,
mich dann langsam in die komplizierteren Klassen einzulesen.
Ich kann auch eine Klasse leichter ändern,
wenn nicht viele andere Klassen davon betroffen sind.
Also wenn ich zum einen nicht andere Klassen, die benutzt werden,
irgendwie damit einbeziehen muss oder auch Klassen, die diese Klasse benutzen,
die Clienten dieser Klasse da nicht von betroffen sind.
Okay, aber das ist erstmal so der Begriff Kopplung,
relativ einfach nachvollziehbar. Was jetzt ganz interessant ist,
ist, dass man explizite und implizite Kopplung unterscheiden kann
Die explizite Kopplung ist genau das, was ihr aus den Klassentriagrammen kennt.
Also wenn Blue Jay hier das so anzeigt,
dann kann Blue Jay das tatsächlich aus dem Quelltext ermitteln.
Blue Jay sieht in der Klasse Graf, gibt es eine Exemplarvariable,
irgendwie Set-of-Knoten, also ist hier eine Abhängigkeit zu Knoten.
Und im Hauptfenster wird so ein Graf erzeugt,
also gibt es hier irgendwo eine Abhängigkeit zum Graf.
Relativ einfach. Kann jeder Compiler ermitteln, man kann durch Quelltextanalyse feststellen,
da ist eine Kopplung da. Eine Abhängigkeit, eine Vererbungsbeziehung,
die ist ja sogar explizit deklariert und so weiter.
Das ist leicht. Was nicht so leicht ist,
ist die implizite Kopplung
Die ist nämlich formal nicht nachweisbar und deswegen auch ziemlich unangenehm.
Ein Beispiel ist ein Entwickler, implementiert sein Wissen über
die Interner eines Dienstleisters in eine Klientenklasse hinein.
Das habe ich hier mal auf einer Folie versucht,
so ein bisschen zu visualisieren. Das ist ein reales Beispiel,
das ich selbst erlebt habe, als ich noch Student war,
habe ich in einem Forschungsprojekt mitgearbeitet und da haben wir eine Plattform gehabt,
eine eigene Hardware, einen eigenen Compiler dafür.
Das war so ein Pascal-Dialekt, so ein Objektnotiertes Pascal.
Und an diesem Compiler haben wir also munter
alle rumgeschraubt
Und da gab es unter anderem so einen fachlichen Behälter,
also einen Behälter, wo Dinge drin waren,
also jetzt nicht Set auf irgendwas, sondern ein,
ich glaube, es waren irgendwie Token,
die der Compiler irgendwie hin und her schieben musste oder ich weiß es nicht mehr ganz genau.
Und es gab einen Klienten, wie ich glaube,
der Compiler selber oder wie, der hat dann diesen fachlichen Behälter benutzt.
Die Details sind nicht so wichtig, ich glaube,
das geht erst mal darum, dass die Grundidee hier verständlich wird.
So, und die Schnittstelle war für diesen Behälter,
also für diese Menge von Elementen, sollten alle Elemente nacheinander geliefert werden.
Das war eine Schnittstelle gefordert,
ich muss sozusagen als Klient über die Elemente iterieren können,
haben wir gerade beim Knoten gesehen oder beim Grafen
So, ja, das war auch implementiert so. Das heißt,
er hat, und das war zufällig die gleiche Person,
wie das dann so ist, man kennt sich ja,
man weiß ja, was im Code drinsteht.
Ja, derselbe Mensch, der das in den Klienten
gebaut hat, hat auch diesen Behälter gebaut.
Und da hat die Implementation halt diese Elemente alphabetisch sortiert geliefert.
Das war nicht gefordert, laut Schnittstelle. Die Schnittstellen waren
tatsächlich explizit beschrieben. Da wurde nur gesagt, alle Elemente nacheinander liefern,
aber die Implementation, zufällig hat das alphabetisch gemacht.
Warum nicht? Das Problem war,
der hier wusste das und hat sich darauf verlassen
Das heißt, hier ist Code, der diese Dinge
nacheinander rausgeholt hat und dann aber schon implizit angenommen hat,
dass die alphabetisch sortiert sind.
Das war vielleicht für die Weiterverarbeitung sehr praktisch.
Ja, so. Jetzt vergehen so ein paar Monate und
jetzt kommt ein Wartungsprogrammierer, jemand anders. Das ist bei
solchen Projekten ja immer so, auch bei unseren solchen Forschungsprojekten.
Da kommt jemand anders dazu. Und der soll jetzt da so
ein bisschen was ändern. Und dann stellt er fest,
ah ja, die Schnittstelle, alle Elemente nacheinander liefern,
die Datenstruktur, in der das Ding neu gebaut wurde,
hat das nicht mehr alphabetisch geliefert.
Es war einfach einfacher, dass irgendwie nach der Einfügereihenfolge zu
machen, wie auch immer.
Hat sich an die Schnittstelle
sauber gehalten
Aber liefert das nicht mehr alphabetisch sortiert? Effekt war,
dass hier kurz zerbrochen ist, also dass da kurz sozusagen nicht mehr funktioniert hat,
weil eben halt implizit davon ausgegangen worden war, dass die alphabetisch geliefert werden. So,
wenn sowas kracht in so einem System, dann rauszufinden,
woran das liegt, das ist extrem schwierig,
das ist extrem blöd, weil da steht ja nicht,
mit blinkendem Warnlicht dran, hier glaubt der Klient,
dass das alphabetisch kommt, das kommt nicht mehr alphabetisch,
sondern das muss man lesen, man muss das erst mal verstehen,
was er da wollte und dann irgendwann kapiert man auch,
Mensch,
der ist da auch von ausgegangen,
dass das alphabetisch kommt
Und wie gesagt, das liest sich nicht mal eben von alleine.
Da muss man das Gehirn anschalten. Das macht es einfach schwierig.
Das Problem ist tatsächlich, dass hier der Klient Wissen über
die Interne von einem Dienstleister in seine Implementation übernommen hat.
Keine gute Idee. Also man sollte nicht zu viel wissen oder
man sollte nicht zu viel von seinem Wissen Gebrauch machen.
Das kann gefährlich sein. Das geht dann auch schon in
die Richtung von dem Geheimnisprinzip, was eben schon erwähnt worden ist.
Das will ich gleich nochmal erläutern. Okay, dann gibt es
auch im Rahmen der Frage, was ist denn Kopplung?
Die Idee davon, dass man geheim eignete Schnittstellen wählen sollte.
Also wie ist denn die Kopplung geregelt? Naja,
über die Schnittstellen üblicherweise in einem Java-System kommunizieren,
Objekte immer nur über Schnittstellen, mit anderen Objekten.
So, und das heißt, diese Schnittstellen legen die Abhängigkeiten fest.
Jetzt gibt es von dem Herrn Horstmann schön mal zusammengestellt in einem Lehrbuch,
so ein paar Entwurfsregeln, wie man denn Schnittstellen bauen sollte.
Die sollten vollständig sein, die sollten klar sein,
konsistent, minimal und bequem benutzbar.
So, das hört sich erstmal richtig gut an.
Das Problem ist, das sind
teilweise konkurrierende Ziele
Wenn ich zum Beispiel minimal meine Schnittstelle halte,
dann habe ich bestimmte fachliche Methoden,
Operationen an der Schnittstelle, die mir etwas liefern.
Jetzt stelle ich fest, in der Benutzung habe ich immer wieder denselben Ablauf.
Ich rufe erst Methode A, dann B, dann C auf,
das brauche ich ganz häufig, diese Zusammenbenutzung nacheinander.
Dann könnte man doch jetzt sagen, naja,
dann stellt halt der Dienstleister eine Convenience-Methode zur Verfügung,
die genau diese drei Dringe zusammenfasst in einer Methode.
Dann ist es nicht mehr minimal, aber es ist
ziemlich bequem benutzbar. Was ist jetzt besser?
Nicht so einfach zu beantworten
Vollständig. Was heißt vollständig? Also wann ist denn
die Schnittstelle vollständig von einer Abstraktion? Wenn man weiß,
wo die Zuständigkeit da liegt, dann kann man das vielleicht eher feststellen.
Aber das ist auch nicht einfach zu beantworten.
Na, sie sollte klar sein, konsistent.
Oh, konsistent ist auch sehr schön. Ich habe hier
ein Beispiel aus der Java-API. Hier Java YouTill. Das
Paket kennt ihr, da sind ziemlich viele Interfaces drin.
Da gibt es eine Klasse, die heißt Date. Datum. So,
und wenn man sich die jetzt mal anguckt,
dann steht hier, Ja, das ist repräsentiert,
ein Specific Instant in time with mily second precision.
Gut. Wunderbar. Irgendwie eine Datumsklasse,
kann man sich ja vorstellen, ein bestimmter Zeitpunkt.
Und jetzt stehen hier so ein paar Eigenschaften. Und da
sieht man hier, hier ist represented by The Integer Y minus
1900. Also das ist sozusagen das Jahr seit 1900. Das ist das,
was da irgendwie modelliert ist. Und dann ist hier gesagt,
Manns ist represented by ein Integer from Zero to Eleven.
Aha. Der Januar ist die Null und
der Dezember ist die
Schön, schön. Und dann Date,
A Day of Months is represent by intenture from one to 31.
So, Informatiker lieben das. Oft bei One-Fehler. Also
fangen wir bei Null an, fangen wir bei eins an.
Ihr fangt ja bestimmt alle bei Null an,
weil so macht man das halt in der Informatik.
Gut, aber die Tage werden hier von eins gezielt,
die Monate von Null. Ich möchte nicht wissen,
wie viele Programmierer sich da schon verhauen haben,
wegen genau so einer Inkonsistenz.
Das ist einfach nicht konsistent. Kann man so machen.
Vielleicht ist das irgendwie aus bestimmten Gründen auch möglicherweise notwendig ist,
so zu machen. Ich weiß es nicht genau,
was die geritten hat, das so zu entwerfen.
Es ist nur nicht konsistent. Und somit auch möglicherweise nicht
so schön in der Benutzung
So, also diese Frage, wie man denn die Schnittstellen wählt,
wie breit man sie macht und so weiter, das ist nicht einfach.
Es gibt aber verschiedene Konkretisierungen. Also was ihr kennt,
sind die Interfaces aus Java. Das heißt,
wir haben ein explizites Sprachkonstrukt bekommen in Java und
das gibt es eben halt auch in anderen Sprachen,
mit denen man eine Schnittstelle explizit beschreiben kann.
Häufig kann man tatsächlich dann die Kopplung zwischen zwei Klassen verringern,
indem man ein Interface modelliert, dass nur die Operationen zusammenfasst,
dass die eine Klasse von anderen benutzt.
Also hier Dienstleister, hier Klient,
Und das Ding hat 20 Methoden und der benutzt nur drei.
Wenn ich aber erst mal hier die Kopplung direkt habe,
dann weiß ich nicht genau, ob jetzt alle 20 benutzt werden.
In so einem Diagramm sehe ich einfach nur Kopplung.
Wenn dazwischen aber ein Interface steht,
dass nur diese drei Operationen zusammenfasst, die der hier braucht.
Und der benutzt das Ding nur über dieses Interface,
dann ist es etwas klarer, die Kopplung.
Da ist eine Meldung. Ja, wenn wir jetzt nur
eine Klasse haben, es wird von mehreren anderen Klassen benutzen.
Kann es sich dann lohnen,
eine solche englischistische Städte für jede der benutzenden Klassen zu machen,
denn die können ja wirklich unterschiedliche Dinge tun.
Vielleicht sollte man
eine Besamtschaft haben
Ja. Sehr schöne, sehr schöne Frage. Also wenn ich
eine Dienstleisterklasse habe und verschiedene Klienten und die verschiedenen Klienten benutzen,
nicht alle die gesamte Schnittstelle, sondern verschiedene Teilaspekte der Schnittstelle.
Ist es dann schlau, da spezifische Interfaces zwischenzusetzen?
Die Antwort ist erstmal ja. Das ist etwas,
was man gut machen kann, weil dadurch diese Abhängigkeiten stärker modelliert werden.
Also wenn man Interfaces als Idee verstanden hat,
dann wird man in diese Richtung
auch arbeiten
Das hat aber auch nicht nur Vorteile. Es erzeugt mehr Abstraktion,
man hat dann mehr Interfaces, aber es ist eben halt die Abhängigkeit explizit modelliert.
Da ist eine Meldung. Sollte man dann jetzt nach Abhängigkeit basieren,
das heißt, wenn wir sagen,
und so ist es halt der Verschwindung, abwürfen,
was du für ein Fahrrad in einem Jahr dazu arbeitest,
heiß war das jetzt, dass man in der Zelle,
in der Vordergrenzung verleihen zu tun hat, die andere,
die andere, das Werk für uns Mittwoch,
das habe ich mitgenommen, Richtig.
Also, was er sagt, ist, ist es denn nicht
vielleicht schlauer, dann diese Interfaces nach fachlichen Zusammenhängen zu modellieren?
Also nicht einfach nur zu sagen, da sind fünf Klienten,
die brauchen fünf verschiedene Subsets der Schnittstelle, also verschiedene Operationen.
Ich habe dann einfach fünf sozusagen mechanisch erzeugbare Interfaces,
ist nicht so eine gute Idee. Dann ist es schon schlauer zu sagen,
naja, ich versuche irgendwie so Aspekte dieser Schnittstelle darzustellen,
also was weiß ich, Iterible, ja,
dann möchte ich sozusagen nur die Methoden zusammenfassen,
um zu iterieren
Bestimmte adjektivische Aspekte, kann ich dann fachlich formulieren.
Das ist dann sicherlich sinnvoll. Also da auch tatsächlich dann zu sagen, naja,
ich muss nicht wirklich für jede mögliche Untermenge von Methoden,
die benutzt werden, ein eigenes Interface bauen,
sondern man versucht das tatsächlich fachlich zu motivieren.
Auch wieder im Sinne von Zuständigkeiten. Also was soll denn über dieses Interface passieren? Okay,
also das kann man auch noch mal so ein bisschen vielleicht konkretisieren,
dieses mit den Interfaces, wie man da auch die Kopplung ein bisschen reduzieren kann.
Das kann ich mal eben zeigen. Was ich nur sagen will,
ist, falls ihr irgendwann mal,
und das solltet ihr irgendwann auf jeden Fall tun,
das Buch in die Hand nehmt hier von Gamma at Al,
also von der Gang of Four über Entwurfsmuster,
dann ist das einer der wichtigen Sätze,
die da auch hinter den Entwurfsmustern steht.
Program to in the interface, not and implementation.
Eine Klasse ist eine Implementation, ein Interface,
in Java ist extra etwas Explizites.
Man sollte immer auf Interfaces hin implementieren. Auch im Eclipse,
in der Implementation werdet ihr sehen,
da ist also exzessiv Gebrauch gemacht worden von Interfaces.
Hier ist ein Beispiel, das kann ich mal hier auch wieder live zeigen.
Ich habe hier, ich mache das mal hier,
klappt das mal auf.
Also tatsächlich, jetzt gucken wir uns mal
die Implementation an
Hier, Hauptfenster und Graf-Panel. Wenn wir uns das jetzt
hier angucken, das ist genau dieses Ding hier.
Wir haben hier den Hauptfenster, das Hauptfenster, das hat so ein paar Buttons.
Und dann gibt es da drin ein Panel. Das ist ein Spezialpanel,
den ich definiert habe, der so in der Lage ist,
so bunte Dinger da hin und her schiebbar zu machen.
Also hier dieser Grafpanel so, der so bunte Klötze anzeigt.
Und was man auch sieht, wen ich den jetzt hier bewege,
so einen Knoten, unten links, dann wird irgendwie die Position angezeigt.
Und unten sind auch so andere Statusmeldungen, die da irgendwie angezeigt werden. So,
das heißt, was wir haben, ist natürlich,
kennt, Kontext, das Kontext-Werkzeug,
das ist ja nicht nach Werkzeug und Materialansatz gebaut,
aber das Kontextfenster kennt natürlich diesen Graph-Panel,
weil wenn da oben neuer Knoten geklickt wird,
dann wird natürlich in dem Ding ein neuer Knoten auch angelegt.
Andersrum muss aber dieser Panel anscheinend ja das Ding da außen kennt,
weil der zum Beispiel hier diese Meldung ausgegeben werden muss.
Das heißt also, wenn hier was passiert,
muss da irgendwie auch was gemacht werden. So,
jetzt könnte man, das ist hier auch auf der Folie angedeutet,
also ich habe hier das Hauptfenster, J. Frame mit einer Meldungszeile und als Center-Komponente diesen Graph-Panel.
So, und jetzt müssen die sich gegenseitig kennen
Zyklische Abhängigkeit. Zwei Objekte müssen sich gegenseitig kennen.
Das war tatsächlich ursprünglich so gebaut,
dass hier Hauptfenster und Grafpanel einfach zyklischen Abhängigkeit hatten zueinander.
Unschön. Und dann war aber relativ schnell erkennbar, naja,
eigentlich braucht der Grafpanel ja nur irgendeine Möglichkeit, eine Meldung rauszuspucken.
Der muss nicht genau wissen, dass das ein Hauptfenster ist.
Also er muss dieses Hauptfenster gar nicht unter seiner vollen Schnittstelle kennen,
sondern der Grafpanel will einfach nur irgendeine Schnittstelle haben,
wo er sagen kann, spuck mal eine Meldung raus.
Und das ist dann hier tatsächlich dieses Interface-Melder,
Ist sehr simpel, ja, melde, eins dringen.
Gib die übergebende Meldung aus. Mir egal wo,
wer auch immer da zuständig ist, der Melder soll da jetzt mal melden.
So, das heißt, der Grafpanel kennt das Hauptfenster nur unter der Schnittstelle Melder.
Und damit ist hier eine zyklische Abhängigkeit aufgelöst über ein Interface.
Relativ einfaches Beispiel, aber dann doch ganz,
ganz illustrativ, wie ich finde.
Ja, also tatsächlich hier die Abhängigkeit per Interface explizit machen,
muss nicht die ganze Schnittstelle kennen.
Hauptfenster implementiert das Interface Melder. Ja, und dann haben
wir genau diese Modellierung hier.
Direkter Zyklus ist aufgelöst
Aber natürlich zur Laufzeit, die Objekte haben dann trotzdem wechselseitig die Referenzen aufeinander.
Das ist nur für den statischen Entwurf, um den klarer zu machen.
Es ist einfach deutlich schneller erkennbar in diesem Diagramm schon,
dass es sozusagen nur dieses Interface,
da dafür da ist, um da was zu melden.
Also zur Laufzeit besteht der Zyklus weiter. So,
eine weitere gute Idee, wenn man Softwaresysteme baut,
ist, Entwurfsentscheidungen zu kapseln.
Das heißt, wenn ihr ein System baut,
müsst ihr ständig
Entwurfsentscheidungen treffen
Das geht gar nicht anders. Ich muss ständig sagen,
ich baue das so und dann baue ich das so und so weiter.
Und was auch eine relativ einfache Einsicht ist, ist,
dass sich jede Entscheidung, die man trifft, auf nachfolgende Entscheidungen auswirkt.
Oder anders gesagt, spätere Entscheidungen basieren auf früheren Entscheidungen.
Wenn man sich für einen Weg entschieden hat,
dann sind von da ab andere Entscheidungen wieder leichter,
weil man sich eben halt auf eine Entscheidung verlassen kann.
So, wenn man einfach sich das so veranschaulicht im Sinne von einer Abfolge von Entscheidungen,
dann ist es eigentlich eine relativ einfache Regel zu sagen,
das, was ich großer Wahrscheinlichkeit selten ändert, das sollte man als erstes festlegen.
Also da, wo man erwartet,
dass es wenig Veränderungen gibt, das ist eine Entscheidung,
die man früh treffen sollte in seinem System. Ja,
also wenn ich zum Beispiel in einem bestimmten Anwendungsbereich aktiv bin und mich mit Versicherungen beschäftige,
dann muss ich halt bestimmte Dinge über diesen Anwendungsbereich,
die werden sich möglicherweise nicht so häufig ändern.
Da muss man natürlich auch dann die Fachlichkeit gut kennen und
dann fragen, wie oft ändert sich das,
wie oft ändern sich die gesetzlichen Rahmenbedingungen und so weiter.
Aber sowas wie ein Vertrag wird es immer geben bei einer Versicherung.
Also das sind so Kernabstraktionen, die ändern sich wahrscheinlich nicht
so schnell. Andere Sachen, Ja,
dieselbe Software soll jetzt mit einer Webschnittstelle benutzt werden oder mit
einer neuen mobilen Oberfläche, mit anderen Bedienelementen.
Die gleiche Software, andere Oberfläche. Dann soll das natürlich
austauschbar sein, diese Technologie. Das heißt also gerade so Benutzungsschnittstelle,
Technologien, welches Persistenzframework wird benutzt, welche Datenbank.
Das sind eigentlich Dinge, die sollte man auch kapseln und dann
auch austauschbar halten. Und man sollte sie später treffen.
Also sie später festlegen. Manchmal ist man da festgelegt durch
den Kunden, aber einfach als Regel Entwurfsentscheidung,
spät treffen die sich häufig ändern können
Und Entwurfsentscheidungen, die sich, also Dinge,
die sich wahrscheinlich nicht so häufig ändern, relativ früh festlegen.
Das ist eben halt nicht so einfach, auch mal wieder,
ja, da kann man jetzt nicht sagen,
das macht man so oder so.
Man braucht eine Menge Informationen über den Kontext,
man braucht halt Erfahrung beim Entwurf und auch ein gewisses Augenmaß dabei.
So, und was wir eben auch schon gehört haben,
eine Ausprägung von diesem Entwurfsentscheidungen, Kapseln ist das sogenannte Geheimnisprinzip.
Ja, und dieses Geheimnisprinzip ist einfach nur relevante Merkmale einer
Entwurfs- oder Konstruktionseineinheit sollten für Klienten sichtbar und zugänglich sein
Das heißt,
ich kann in einer Klasse oder in einem Subsystem oder in einem Paket Dinge kapseln,
sozusagen nicht für Klienten zugänglich machen und habe dann den Vorteil,
dass ich dann die Entscheidungen, die ich innerhalb dieser Kapsel treffe,
ändern kann, ohne dass Klienten davon betroffen sind.
Je mehr ich Dinge kapseln kann, vor Klienten schützen kann,
desto mehr kann ich da auch, habe ich meine Freiheit,
da was zu ändern.
Das gibt uns Flexibilität als Entwickler. Das ist gut. Also das Geheimnisprinzip,
da geht es nicht darum, irgendwas zu verstecken,
sondern es geht darum, Klienten davon abzuhalten,
Dinge auszunutzen, die in der Implementation irgendwie sind.
Wir haben das schon bei der impliziten Kopplung gesehen,
aber auch allgemein ist es einfach gut,
wenn Dinge erstmal nicht nach außen veröffentlicht werden.
Wie gesagt, schon an das Wissen über Interna kann missbraucht werden.
Dieses Geheimnisprinzip, das geht auf einen auch absolut klassischen Artikel
zurück von David Parners. Auch wieder, was jedem seriösen
Softwarearchitekten empfehlen würde, um irgendwann mal gelesen zu haben.
Diese Idee, wie man denn ein System in Module
zerlegen kann. Damals war das zu der Zeit,
als er das geschrieben hat, war noch so,
wir haben den Kontrollfluss, eine Anwendung, wir haben Top-Down-Entwurf.
Wir verfeinern schrittweise, indem wir entlang des Kontrollflusses immer weiter runtergehen.
Step-vised refinement. Entlang des Kontrollflusses der Anwendung. So,
und da hat er gesagt, nö, machen wir ganz anders.
Wir machen das danach. Wir kapseln die Entwurfsentscheidungen und das
ganze System besteht eigentlich aus solchen Kapseln um Entwurfsentscheidungen.
So, und das war erstmal überhaupt nicht verständlich.
Die meisten Leute haben überhaupt nicht kapiert, was er sagen wollte,
dass das eine der Grundlagen ist für Objektorientierung,
ist ja erst Jahre später sozusagen einigen Leuten aufgegangen.
Es gab auch Leute, die haben ihn dafür gedisst,
was er gesagt hat.
Und Jahre später wurde er
dann rehabilitiert
Also er ist einer der ganz Großen in der Informatik,
was Software-Technik angeht, David Parners.
Von dem könnt ihr eigentlich fast alles lesen.
Was der schreibt, ist immer schlau.
Gut, Zyklen vermeiden, haben wir auch schon gesehen.
Dieses eine Beispiel habe ich gezeigt. Eine ganz banale Regel,
vermeide Zyklen. Warum sollte man Zyklen vermeiden? Naja,
auch wieder, wenn ich solche Zyklen habe,
dann kann ich die schlecht unabhängig voneinander testen.
Weil ich weiß ja nicht, welche ich jetzt zuerst testen kann.
Ich kann die ja gar nicht unabhängig testen.
Initialisierungsreihenfolge ist möglicherweise auch unklar, wenn Zyklen in einem Klassengrafen
zu sehen sind
Es gibt keinen offensichtlichen Einstiegspunkt, um dich in den Entwurf einzulesen.
Das heißt also, Zyklen gelten als eines der Grundübel von Softwarearchitekturen.
Versucht erstmal, die zu vermeiden. Aber und
da bin ich sozusagen eher auf der etwas entspannteren Ebene.
Es gibt Leute, die sind wirklich Evangelisten,
die wollen gar keine Zyklen, auf keinen Fall.
Ich denke, man muss unterscheiden. Es gibt Bereiche oder Situationen,
wo man sagen kann, Objekte, die sehr sicht zusammenhängen,
die können sich ruhig gegenseitig kennen.
Zum Beispiel ist es so, geschachtelte Klassen,
habt ihr auch schon kennengelernt in Java, die kennen sich gegenseitig sehr gut.
Die sind eben halt auch sehr dicht zusammen.
Wenn Dinge sehr dicht zusammenstehen, ist es gut,
wenn die sich gegenseitig kennen
Sagen wir nicht so schlimm,
weil man ja als Wartungsprogrammierer die Dinge im Zusammenhang hat.
Schwieriger wird es, wenn die Zyklen über größere Ebenen gehen.
Also wenn ihr einen Zyklus habt,
der über mehrere Pakete geht, dann ist es relativ schwer,
den erstens zu erkennen und dann zweitens auch diese Abhängigkeit aufzulösen.
Und sowas baut man sich relativ leicht. Ich sehe auch gerade,
jetzt habe ich schon die Pausenzeit lange überschritten,
machen wir gleich eine Pause, vielleicht nochmal eben hier.
Unsere Entwurfsregeln, die wir euch gegeben haben,
die geben euch ja auch eine gewisse Anleitung
wie ein System zu bauen sein soll und benennen unter anderem
diese vier Elementtypen
Ja, also das sind hier die Elementtypen. Und da haben wir
ja auch die, sagen wir, zulässigen Abhängigkeiten mitmodelliert.
Ja. Und wenn man sich daran hält und dann auch die entsprechenden Pakete baut,
wo dann diese Dinge drinstecken,
dann kann man eben halt auch auf der Paketebene diese Abhängigkeiten danach modellieren und kann sagen,
naja, tatsächlich wird es nicht so sein, dass irgendetwas aus dem Materialienpaket auf etwas im Werkzeugpaket zugreift.
Wenn das passiert, ja, man kann solche Abhängigkeiten ja
mit manchen Tools auch erkennbar machen. Es gibt tatsächlich Software,
die nichts weitermacht als Abhängigkeiten zu visualisieren in solchen objektnotierten Systemen,
teilweise sehr groß, diese Systeme, mit mehreren 10.000 Klassen.
Und dann kann man schon mal sehen, oh,
da ist plötzlich ein Rückbezug, kann eigentlich nicht sein,
weil eigentlich diese Entwurfsregeln sagen, dass diese relativ strikt geordnet sein sollen, diese Abhängigkeiten.
Also dadurch, dass man diese Entwurfsregeln hat,
werden die Entwurfsregeln bewirken dann auch aus transitiv zum Beispiel keine Paketzyklen entstehen.
Gut, dann würde ich sagen, machen wir jetzt mal eben fünf Minuten Pause. Dann machen wir weiter. Ich habe jetzt hier die Sache mit den Zyklen so ein bisschen motiviert,
ein weiteres Entwurfs, eine weitere Entwurfsrichtlinie, die schon damals,
als sie Law oft die Mieter genannt wurde,
eigentlich nur eine Entwurfsrichtlinie war, ist das,
was ich jetzt hier vorstelle, auch wieder Ende der 80er,
objektrentiertes System, die haben da so Entwurfsregeln festgelegt,
aus anderen Gründen, die dann auch hinterher teilweise kritisiert wurden,
die man also sehr datengetrieben in ihrem Entwurf,
aber die hatten eine bestimmte Entwurfsrichtlinie, die sagte,
und die ist einfach interessant, diese Entwurfsrichtlinie,
wenn du das mal irgendwo nachlesen wollt,
ist das irgendwie auch ganz spannend
Für eine Methode M eines Objektes O.
Ich habe ein Objekt und da ist eine Methode.
So, ihr wisst ja irgendwie, Objekt kann ein Exemplar-Variament haben.
So, jetzt wird eine Methode aufgerufen.
Und was soll innerhalb dieser Methode jetzt aufgerufen werden können?
Oder was sollte man aufrufen dürfen? Dann ist es erstmal klar,
dass ich natürlich die privaten oder öffentlichen Methoden des Objektes benutzen kann in der Methode.
Also alles von die Methoden von O selbst.
Dann bekommt die Methode M möglicherweise Parameter,
die bekommen es wahrscheinlich, damit sie benutzen kann.
Also sollte es da auch durchaus
Methoden aufrufen können
Alles, was innerhalb der Methode erzeugt wird,
macht auch Sinn, dass man da irgendwas mit machen will.
Also kann man die auch aufrufen. Und von Exemplarvariablen von O. Klar,
also in der Methode kann ich natürlich auch auf bestimmte...
Auf alle Exemplarvariablen von O. zugreifen. Aber auf nichts anderes.
So, und was heißt das jetzt? Das heißt zum Beispiel,
wenn ich einen Parameter bekomme, dann rufe ich an den Parameter nicht auf,
gib mir mal das nächste Objekt und das nächste Objekt.
Und dann daran rufe ich irgendwas auf. Dann hat man
schon das Law auf die Mieter gebrochen. Umgangssprachlich könnte man auch sagen,
sprich nur mit deinen engsten Freunden, also im Sinne von,
Versuche nur die Methoden aufzurufen von den Dingen, die wirklich in unmittelbarer Umgebung sitzen.
Und Hinweise auf Verletzungen vom Love, die Mieter, sind solche Sachen hier. Irgendwie sowas wie Student,
Get Record, Get Axem Entry, SE 2006,
Ed Result 93. Also irgendwie geht es möglicherweise darum,
dass in einem System wie Stine bei einem Studenten in sein Leistungsportfolio eingetragen werden soll,
irgendwie aus einem Exem Entry das Result von,
das ist jetzt hier konstruiert, aber so eine Kette,
die da tatsächlich ausprogrammiert ist.
Warum ist das so schwierig? Warum ist das
so problematisch
Weil da eine hohe Kopplung mit definiert ist.
Also so eine lange Aufrufzeile koppelt stark. Warum? Naja
, ich habe den Klienten, der das Ding aufruft.
Also irgendwo in irgendeinem Klientencoach steht ja dieser Aufruf drin.
So, der kennt schon mal den Student.
Bei dem Student wird ja irgendwie jetzt aufgerufen, Get Record.
So, dann hat der Student anscheinend einen Record irgendwie,
kennt er wieder als Typ.
Und das kann man sich geben lassen. So,
und jetzt wird da dran wieder Get Exam Entry aufrufen.
Das heißt, der Klient ruft daran Get Exam Entry auf.
Und dann muss er also auch tatsächlich und das wieder kennen
und das auch benutzen. Das heißt,
jetzt ist dieser Code hier in dem Klienten gekoppelt mit dem Studentencode,
mit dem Recordcode und mit dem XMM-Entry Code.
Und das ist ein Traversieren eines Objektgeflechtes.
Das ist irgendwie ein Objektgeflecht von Student Record und Xame Entry.
Und so, und das ist aber da tatsächlich jetzt in
einer Quelltextteile hart gecodet, steht das da.
Das heißt, wenn ich jetzt diese Struktur ändern will,
also irgendwie sagen will, die Zusammenhänge sollen anders werden,
dann steht aber hart in dieser Zeile jetzt
diese Abhängigkeit so reinkodiert
Das heißt, wir koppeln den Rumpf dieser Methode stark an eine bestehende Struktur.
Und das verändert erschwert Veränderungen. Wie gesagt,
das ist viel diskutiert worden, dieses Lauf,
die Meta, auch viel kritisiert worden,
weil es eher aus einem datengetriebenen Entwurf kam,
aber als zeitgemäße Anpassung für Entwurfsringen gibt es eben halt diese Dinge hier,
die ich auch alle aus der Literatur mit zusammengesucht habe.
Also if you delegate delegate fully,
also wenn ihr irgendetwas haben wollt, dann könnt ihr euch
durch eine bestimmte Struktur durchhangeln und euch das selbst holen.
Oder ihr sagt, dem Objekt in eurer Umgebung,
du gibst mir das jetzt
Also ihr delegiert tatsächlich das an eure direkten Nachbarn,
dass die euch das liefern, was ihr braucht.
Wenn die es nicht können, dann müssen die halt wieder
entsprechend arbeiten. Aber da sollte irgendwie so sein,
dass die Aufgaben von der direkten Umgebung erfüllbar sind.
Andere Ausprägung ist don't message your delegates, objects, objects.
Also genau, was ich gesagt habe,
ihr bekommt einen Parameter, dann ruft ihr daran auf,
gib mir das und das und dann daran wieder.
Also man soll eigentlich nicht an die indirekten Objekte
schon wieder Nachrichten schicken, also da Methoden aufrufen.
Don't be a where of house some object works,
don't work at a lower level than is necessary.
Das ist das Beispiel mit der Vormerkkarte
Ja, der Klient bei den meisten Implementationen,
die ich gesehen habe, der Klient, der Verleihservice,
weiß, wie die Formel-Karte aufgebaut ist, sagt,
Mensch, ich muss mal eben prüfen,
ob der Vormerker da rauf kann auf die Karte.
Ich frage nicht die Karte, sondern ich, Karte,
gib mir mal deine Cue und ich wühle selber mich durch die Cue durch.
Dann geht man eigentlich in die Implementation der Karte rein,
weil man ja weiß, wie es gebaut ist und lässt
sich das alles rausgeben und wühlt da in den Eingeweihten rum.
Statt zu sagen, hey, Karte, beantworte mir die Frage,
ist da noch Platz bei dir auf der Karte?
Das ist genau diese Idee von auch diesem sehr knappen
Entwurfshinweis,
Tell down
Also sage, sagt dem Objekt in deiner Nachbarschaft,
was es tun soll und frage es nicht nach,
irgendwelchen Details und das ist der Hakel da selber durch.
Auch das ist natürlich immer wieder letztendlich mit dem Law auch beim Law auf die Mieter.
Wer sollte denn für eine bestimmte Aufgabe zuständig sein? Also hier zum Beispiel,
wenn wir jetzt so eine Aufrufkette haben,
dann könnte man vermutlich es besser machen,
dem man sagt, aha,
in der klassischen Student gibt es irgendwo eine Operation,
da wird jetzt ein Score eingetragen und dieses Markt XM ist möglicherweise irgendwie ein Objekt,
das die Examensergebnisse hält und dann wird in dieser Methode Score einfach implementiert,
wie dann aus dem Markt Exembers rausgeholt wird.
Das heißt, dann muss ich als Klient des Studenten nicht mehr genau wissen,
wie der, das ist jetzt irgendwie intern aufgebaut ist,
sondern mache das deutlich eleganter.
Ein anderes Beispiel ist, man fragt nicht einen Satelliten,
das seinen Antriebsdüsen und sagt dann irgendwie so,
jetzt gib mal da mehr Gas,
sondern ich sag einfach dem Satelliten, I tell don't ask.
Also gib mir mal deine Antriebsdüsen, ich mach mal eben irgendwie,
sondern Satellit, ich sage jetzt,
ich sage dem Satelliten, richte dich neu aus.
Das muss die Schnittstelle einfach hergeben. Getter und Setter sind so ein typisches,
typisches Beispiel für Verstöße gegen das Law auf die Miete.
Und das hat hier der gute Deakin auch nett beschrieben. So,
wenn Leute immer wieder sagen, oh, ich weiß ja,
die Exemplar war ja, sind ja da, ich brauche mal,
schreib mal in meinem Ghetter und lass mir alles geben.
Und dann kann ich damit ja weiter arbeiten. Dann ist
die Schnittstelle gar nicht als als, als fachliche Schnittstelle gebaut,
sondern nur einfach nur, da sind Daten zusammengesteckt,
ich hole sie mir raus und travisiere eine Datenstruktur letztendlich.
Also da kann man relativ viel dran sehen,
dass dieses Law auf die Mieter gar nicht so,
ja nicht so doof ist.
Also immer, wenn ihr solche lauren Aufrufketten seht,
solltet ihr zumindest euch überlegen,
ob das ein Problem geben könnte.
Jetzt sozusagen der zweite wichtige Begriff. Wir haben jetzt Kopplung
so ein bisschen in verschiedenen Ausprägungen diskutiert.
Der zweite wichtige Begriff ist Korrision. Und das ist der
Grad der Aufgaben, die eine Softwareeinheit zu erfüllen hat.
Während eine Softwareeinheit viele Aufgaben erfüllt, ist ihre Korrision schlecht.
Dann ist ihre Korrision niedrig. Also möglichst hohe Korrision heißt,
möglichst klar, idealerweise eine Aufgabe.
Also wir können tatsächlich auf der Ebene von jetzt wieder für
Objekte unter die Systeme vom Klassenentwurf unterscheiden bei Methoden.
Wie ist die Korrision und bei Klassen
Nur einfach nochmal hier so was ganz, ganz Illustratives für diesen Begriff,
der ja so ein bisschen fremdwortartig daherkommt, Kohision.
Es gibt einmal den Begriff so vorne vom Ursprung her in der Chemie und der Physik,
molekulare Kraft zwischen den Molekülen eines Stoffes,
also quasi der innere Zusammenhalt eines Stoffes.
Also wenn etwas irgendwie gut zusammenpasst, irgendwie stimmig ist,
dann ist es, dann hat es eine hohe Kurision.
Und in der Link Wisley gibt es den Begriff auch,
und da ist es eher so Verknüpfung von bestimmten Elementen zu einer sinnvollen Einheit.
Also auch da wieder sinnvolle Einheit, ja,
das passt gut zu unseren objektorientierten Entwürfen und euren objektorientierten Systemen
Ein Beispiel für eine niedrige Korision. Eine Methode sollte nur für genau,
also Korision von Methoden, eine Methode sollte nur für genau eine,
obwohl definierte Aufgabe zuständig sein.
Hier hat jetzt jemand sowas gebaut, es gibt eine trigonometrische Funktion,
also sozusagen, die kann alle trigonometrischen Funktionen.
Und man übergibt als Parameter, welche Funktion man berechnet haben
will und dann natürlich noch das Argument für die Funktion.
Da hat vielleicht jemand gesagt,
hm, die Schnittstellen müssen klein sein in unserem System,
keine Klasse darf mehr als sechs Methoden haben, so.
Na gut, dann passt das ja nicht rein,
dann fange ich an, das zusammen zu quetschen.
Schmeiße ich irgendwie eigentlich mehrere Methoden in eine
Da ist es eigentlich schlauer zu sein, naja,
es gibt eben halt eine Methode für den Sinus,
für den Cosios und den Tangames.
Das ist dann, da ist die Koission für die Methode einfach.
Klar, das ist die Methode für den Sinus und für
den Cosios und so weiter. Das kann man so machen wieder links,
aber das ist möglicherweise jetzt nicht so die wirklich tolle Koission an der Stelle.
Koisson von Klassen, das ist so hier so ein ziemlich komisches Beispiel,
habe ich irgendwo aus einem Buch mal rausgeholt.
Also initialized Command Stack, Popcoman, Shutdown,
Command Stack, Initialize, Format, Print,
da ist irgendwie alles reingeschmissen worden,
was sonst keinen Platz hatte
Irgendwie so, so die Sammelklasse, wo dann ganz viele
verschiedene Methoden reingeworfen wurden. Während bei der Klasse Film,
ich sehe die Meldung, bei der Klasse Film,
man wirklich sagen kann, naja, hier,
das modelliert einen Film mit bestimmten Eigenschaften, die klar umrissen sind.
Das ist hohe Kurse. Und da ist eine Meldung.
Ja. Dass der praktisch die Kinder von der Abbrüche tut.
Er verbrannt jetzt die Meldung. Er beginnt jetzt die Vereidigung der Karte
. Sattel und die Gelegenheit, die der eigene Freiheit.
Das wäre auch tut man da für alles in der eigenen Berufsanfälle.
Da würden wir das bedienen und jetzt verbrennen. Okay,
also ich habe das jetzt so verstanden, dass du sagtest,
dass es in diesem Fall vielleicht noch nachvollziehbar ist, aber es gibt so Dinge,
wo man so Notify hat und dann mit verschiedenen Ereignissen benachrichtigt wird.
Und dann wäre es ja blöd,
wenn man dann für jede Nachrichtenart eine eigene Methode baut,
sondern man macht das eben halt in ein Eventobjekt rein,
das dann sozusagen, ja, natürlich ist das jetzt keine,
das Beispiel sollte jetzt nicht wieder transponiert werden auf alle möglichen Entwurfssituationen,
was einfach nur klar sein sollte, ist, Erstmal,
dass ihr das Gefühl dafür habt,
was heißt überhaupt Kollision von einer Methode?
Und man sagt halt, hier ist einfach,
in dieser Methode steckt deutlich mehr drin,
mehr Zuständigkeit als in diesen einzelnen Methoden.
Das kann vorteilhaft sein. Das muss aber nicht immer
vorteilhaft sein. Also beim Beobachtermuster ist es wahrscheinlich schlau,
dass man da irgendwie den Verursacher des Events irgendwie als Parameter übergibt.
Und dann eben halt nicht für jedes Event eine eigene fachliche Methode baut.
Klar. Kollison von Klassen. Ich habe nochmal das Beispiel
hier mit der Mediathek. Wenn ihr euch erinnert,
wenn wir das Ding hier gestartet haben,
läuft das nicht noch?
Habe ich hier
nicht das irgendwo noch laufen
Da. Dann habe ich ja hier das Kontextwerkzeug, und das hat mehrere Subwerkzeuge.
Also hier hat man den Kundenauflister, hier hat man den Medienauflister,
hier hat man den Kundenanzeiger, hier hat man den Medienanzeiger.
Also alles Subwerkzeuge. Man hätte natürlich alles in eine Werkzeugklasse schreiben können.
Das ist eine relativ komplexe Oberfläche hier. Es gibt viel,
viel komplexere, aber das ist schon relativ komplex.
Und wenn man das jetzt alles in eine Oberfläche,
in eine Gui schmeißen würde, würde das Ding ziemlich komplex werden.
Und es wäre auch, was wäre das? Na gut,
das wäre die Vormerkansicht, ist eigentlich ja beschreibbar,
die Korrision ist da, das geht ums Vormerken,
gut, gut, aber es ist schon gut,
dann auch Subwerkzeuge zu haben, die dann sagen,
hier geht es nur darum, Kunden aufzulisten, das Kundenauflister-Werkzeug.
Also auch da sieht man jetzt,
die Korrision dieser einzelnen Werkzeuge ist dann schon relativ klar definiert.
Die haben nur eine hohe Kollision. Okay, dann gibt es
so ein paar andere Entwurfsregeln, so zum Beispiel geeignete Bezeichner wählen.
Ihr kennt möglicherweise so verschiedene Hinweise aus so Lehrbüchern,
Allgemein kann man sagen, eine konkrete Klasse sollte natürlich ein treffendes Substantiv benennbar sein.
Also üblicherweise benennen wir Klassen mit Substantinen. Das ist schon dann nicht mehr ganz zutreffend,
wenn wir uns Interfaces ansehen, aber da wissen wir ja,
es gibt ja so adjektivische Interfaces, so wie Comparable, Iterible.
Aber bei Klassen ist es schon eigentlich bei konkreten Klassen,
ein Interface ist ja keine konkrete Klasse, ist es meistens sinnvoll.
Eine Methode durch ein treffendes Verb, das ist relativ einfach,
diese Regeln einzuhalten, was man aber häufig als schlechten,
also als einen Hinweis auf schlechte Korrisionen nehmen kann, sind solche Unbezeichner.
Einfügen und berechnen oder Starter und Vermittler. Also immer,
wenn da so ein Hund im Klassennamen steht oder in den Methoden nahm,
dann ist das schon so ein Hinweis,
dass die Korrision nicht so richtig gut ist.
Da werden eigentlich zwei Dinge gemacht in dieser Methode.
Eine extreme Ausprägung von diesem geeignete Bezeichner wählen ist tatsächlich,
dass man den Quelltext so schreibt,
dass der Kunde ihn sogar selbst lesen kann.
Also ein Kunde, der nicht programmieren kann, dass der das lesen kann.
Also wenn ihr euch jetzt dieses Beispiel hier anguckt und ihr redet mit einem Mathematiker,
Es ist möglicherweise für den relativ schnell nachvollziehbar,
welche Schnittstelle hier der Graf hat, an welcher Schnittstelle der Knoten hat.
Also ein Knoten in einem Graf und was der Graf
an Operationen hat, an Umgangsformen.
Damit, das kann man mit einem Mathematiker besprechen.
Wenn da jetzt noch Code drin wäre, der dann dafür sorgt,
dass zum Beispiel so ein Graf beobachtbar wird.
Und dann sozusagen die Gui sich dann verändert,
wenn der Graf sich ändert, dann mischt ihr plötzlich technischen Code mit fachlichem Code.
Und dann ist es möglicherweise nicht mehr so lesbar.
Also hier können wir tatsächlich die pure Fachlichkeit in diesen beiden
Klassen drin haben und können die mit dem Kunden
in Anführungsstrichen
auch diskutieren
Das ist tatsächlich auch in Versicherungsprojekten, in denen ich dabei war,
teilweise so gewesen, dass dann Leute aus der Fachabteilung,
mit denen konnte man dann über diese Klassen diskutieren,
über die fachlichen Klassen.
Okay. Eine Frage, die ich ganz oft gestellt bekomme,
also auch von Kollegen so auf Konferenzen so, na,
wie macht ihr es denn, wenn ihr Objekte,
die Programmierungen lehrt bei euch an der Uni?
So die Verwendung von deutschen oder englischen Namen.
Also so der Klassiker, klar, alles Englisch,
so viel cooler. Oder Valjava ist ja Englisch weitgehend,
das liest sich ja so wie Englisch,
also sollten auch die ganzen Bezeichner
alle Englisch sein
Und sowieso, wir sind hier an der Uni,
wir machen alles nur auf Englisch. Das ist viel internationaler.
Klar, kann man alles so sagen. Man kann auch sagen,
es muss alles einheitlich sein in einer bestimmten Sprache.
Die Antwort, die wir hier geben, ist eigentlich eine andere.
Es gibt einfach keine abschließende Antwort. Das ist davon abhängig,
nämlich für jedes Projekt ist es einfach, muss man
sich das neu überlegen. Und was wieder dabei hilft,
ist, wenn ich fachliche und technische Klassen trenne,
das kennt ihr, unsere Entwurfsregel legen das ja auch nah,
dann sollte man technische Klassen auch mit englischen Namen benennen
Also, Frame, Button, Listener, Writer,
Transaction, all sowas, was technisch motiviert ist,
aus einer Framework-Klasse kommt oder ähnliches, die sollten Englisch benannt sein.
Und für die fachlichen Klassen kommt es halt darauf an,
ob der anwendungsfachliche Zusammenhang deutsch ist oder Englisch.
Wenn ihr bei einer deutschen Versicherung in einem Projekt sitzt und
mit denen über Verträge redet und über Laufzeiten und so weiter,
dann wäre es ziemlich komisch, dann künstlich das alles auf Englisch zu schreiben.
Contract, Runtime oder sowas. Das bildet dann einfach das
ab in eine andere Sprache und dabei kann Unschärfe entstehen,
die möglicherweise nicht so hilfreich ist.
Da ist eine Frage
Da ist schon das, was ich mich da vermaßen kann.
Bitte? Was ist mit dem auch nicht immer besser,
dass man, wenn man nicht beklappt, auch nicht aus dem Außenplatz.
Okay, also er sagt, was ist denn,
wenn man jetzt gezwungen ist, Entwickler aus dem Ausland mit einzubeziehen?
So, jetzt könnte man sagen, na, ganz klar,
alles auf Englisch. Nö, ist nicht klar.
Weil die Fachlichkeit bleibt ja Deutsch. Also das,
was da passiert, muss ja auf Deutsch möglichst exakt abgebildet werden.
Dann muss derjenige, der da kommt,
ich kann eben halt nicht irgendwie jetzt irgendjemand x-beliebiges einkaufen,
der kann Deutsch, kann und ein deutsches Anwendungssystem setzen.
Das funktioniert ja nicht, weil es muss ja das Problem
in dem deutschen Kontext gelöst werden.
Er muss ja verstehen, was da passiert
Das heißt, man kann natürlich jemanden ins Projekt holen,
der guter Programmierer ist und dann die technischen Tassen manipulieren lassen.
Aber das muss nicht der Grund sein, dass man deswegen die fachlichen Klassen Englisch modellieren muss.
Spricht nicht unbedingt dafür. Aber wenn man tatsächlich,
wie du sagst, also wenn man sagt,
man hat eben halt internationale Beteiligung, also gerade bei Forschungsprojekten,
ja, hier an der Uni, Robotikprojekte,
wo man einfach mit Wissenschaftlern zusammenarbeitet, da ist es relativ offensichtlich,
dass man das auf Englisch macht.
Weil dann der Quelltext ja auch international begutachtet werden soll.
Wenn ihr bei Open-Source-Projekten mitarbeitet, ihr auch sicherlich das auf Englisch machen,
damit es der Weltöffentlichkeit auch besser zugänglich ist.
Es ist nur aber eben so, es gibt Kontexte,
in denen das einfach nicht opportun ist,
wo man tatsächlich es mit einer bestimmten Fachlichkeit zu tun hat,
die man dann deutsch abbilden kann.
Und dann ist das auch in Ordnung. Also das ist
unsere Sicht darauf. Ich meine, das ist ja hier kein Evangelium.
Wir differenzieren das eben halt einfach und sagen nicht,
es muss immer alles Englisch gemacht werden.
Das ist tatsächlich nicht so hilfreich. Das führt ja dazu,
dass dann tatsächlich in der Mediathek zum Beispiel das gemischt ist,
führt zu so einem Flickenteffich, so deutsche und englische Begriffe gemischt,
ist das nicht ganz schrecklich
Kann man als hässlich empfinden? Man kann es auch als Chance
sehen. Weil tatsächlich in den Bezeichnern viel klarer wird,
was ist Fachlichkeit und was ist Technik.
Also hier, wir haben tatsächlich in der Mediathek diese Beispiele.
Wir haben einen Bearbeiten-Button. Naja, klar, fachlich wird da etwas bearbeitet.
Und das ist ein Button. Technisch ist es einfach eine Schaltfläche.
Get Medienart. Wir haben nicht gesagt, gib Medienart,
sondern wirklich so ein Getter, der einfach das Ding nur ausliest.
Das ist ein technisches, reicht es mir raus,
wenn wir bewusst Get Medienart.
Medienart ist das Fachliche. Get ist das Technische.
Rückgabe UI. Es geht um die UI für die Rückgabefunktionalität
Das ist fachlich die Rückgabe, und das ist eine UI,
also ein User-Interface auf Englisch.
Okay. Nochmal, was ist eine Todsünde? Genau.
Einen Namen mit Umlauten. Ah, okay. Ja,
das ist jetzt hier auf der Folie wahrscheinlich so reingerutscht.
Rückgabe mit Ü. Das ist nicht unbedingt eine Todsünde.
In Java geht das ja sogar, aber ich würde auch
vorsichtig sein, das zu machen.
Das würde ich in keinem Software-System tun.
Also er sollte wahrscheinlich eher UE stehen. Ja,
danke für den Hinweis.
Dann noch eine Konkretisierung, möglichst genaue Bezeichner wählen.
Das ist etwas, das habe ich bei dem Herrn Pugh nachgelesen.
Das fand ich irgendwie ganz cool. Der hat ein Buch
geschrieben, das heißt Prefactoring. Also wenn man Software baut,
dass man nicht möglichst schnell was zum Laufen bringt,
also sozusagen die Gegenbewegung zum Agilen, möglichst schnell laufenden Code.
Er sagt, ruhig beim Entwurf, sehr genau hingucken und schon sehr genau differenzieren.
Die Begriffe, die man im Anwendungsbereich erkennt,
möglichst scharf zu differenzieren. Weil er sagt,
in jedem Softwaresystem ist verschmelzen leichter
als aufteilen
Wie soll man das jetzt verstehen? Gut, ein Beispiel wieder unserer Mediathek-CD-Verleih.
Wir modellieren zu Beginn als zentrale Abstraktion die Klasse CD,
haben wir ja gemacht in der Mediathek. So,
später stellen wir fest, wir müssen die Modellierung eines Albums,
ein konkretes Album von einem bestimmten Künstler,
mit einem bestimmten Namen, unterscheiden von,
das Album kann mehrfach angeschafft sein und natürlich auch mehrfach ausgeliehen werden.
Früher waren ja diese Medien noch irgendwie physisch,
da musste man sie ja noch verleihen.
Heutzutage ist das wahrscheinlich für euch gar nicht mehr nachvollziehbar.
Und wenn man das später feststellen,
hat das System schon gebaut, hat erstmal nur eine CD-Modell.
Oh, jetzt muss man das differenzieren. Wir brauchen jetzt einfach,
wir brauchen jetzt eigentlich zwei Begriffe. Eigentlich so das Album
und das andere ist so die ausleihbare CD oder irgendwie sowas.
Also ich muss mir erstmal einen Namen überlegen und muss dann
an allen Stellen, an denen bisher CD verwendet wurde,
gucken, ist es das oder ist es das,
was da gerade an der Stelle benutzt werden musste.
Wenn man von vornherein differenziert modelliert hätte,
also diese Begriffe von Anfang an getrennt hätte und dann irgendwann feststellt,
ach, die Trennung brauchen wir eigentlich gar nicht,
dann ist das ziemlich leicht,
sozusagen an allen Stellen,
an denen diese Begriffe jetzt verwendet werden,
das abzubilden auf eine
Es ist Verschmelzen, ist tatsächlich technisch viel einfacher als dieses nachträgliche,
jede Stelle angucken müssen und sich entscheiden müssen,
das ist das eine oder das andere.
Ganz banal. Das heißt, das ist ein gutes Argument,
sehr, sehr genau zu analysieren und auch schon Begriffe
möglichst scharf zu kriegen, wenn man analysiert.
Das ist eben halt auch wieder ein weiteres Argument dafür,
dass in der Sprache des Anwendungsbereichs zu tun,
weil die Schärfe sonst möglicherweise verloren geht.
Gut, Kot-Uplizierung vermeiden. Auch wahrscheinlich eine gut nachvollziehbare Regel.
Wenn ein Schritt Quelltext in identischer Form an mehreren Stellen
definiert ist,
sprechen wir von Kot-Uplizierung
Ja, ich hatte das Beispiel eben schon mit diesem Travisieren des Knotens,
um seinen Grad zu ermitteln, wenn der Code jetzt nochmal woanders stünde, hätten wir jetzt schon zwei Stellen.
Hier ist zum einen gesagt, das ist ein Zeichen niedriger Korhision,
also an mindestens einer von den beiden Stellen ist es eigentlich nicht angebracht.
Wahrscheinlich gehört es an keine der beiden Stellen, sondern in den Knoten selbst rein. Es ist aber auch eine implizite Kopplung,
weil wenn ich feststelle, dass dieser Code,
der an mehreren Stellen steht,
falsch ist und ich stelle das an einer Stelle fest,
ich gucke mir den Code an, sehe, oh,
da ist irgendwie was, das ist nicht ganz richtig gemacht,
er hätte das eigentlich ein bisschen anders machen müssen,
dann wird das an der Stelle korrigiert,
wenn man es bemerkt,
aber man weiß ja nicht,
dass der Code noch an der Stelle und an der Stelle
auch nochmal steht
Da ist ja kein Verweis dafür. Das ist eine implizite Kopplung. Das heißt,
das geht mir verloren, dass ich dann an der Stelle
das korrigiert habe und an anderen Stellen nicht korrigiert habe.
Im Sinne von, man schafft es sich da jetzt
nur ein paar Meter verändern. Die Frage ist,
was passiert, wenn Code nur einfach sehr ähnlich ist?
Also unterscheidet sich möglicherweise nur in einem Parameter. Ja,
also es ist immer dann schon gut, das überhaupt zu bemerken.
Und dann kann man sich überlegen, wie man den Entwurf ändert.
Vielleicht ist das sehr sinnvoll, dass es an zwei
verschiedenen Stellen mit verschiedenen Parametern passiert
Wenn die Ähnlichkeit sich nur an einem Parameter befindet,
könnte man eben halt auch überlegen, das zusammenzufassen.
Aber das ist natürlich immer eine Frage der Zuständigkeiten.
Passt das irgendwo hin? Also da gibt es auch wieder
keine schwarz- oder weiße Antwort drauf.
Aber es ist natürlich genau diese Frage. Wenn das in
diese Grauzone reinkommt, was macht man da jetzt?
Gut, große Einheiten vermeiden. Die Gottklasse ist eigentlich nichts Schönes.
Habe ich aber oft genug gesehen. Also so Leute,
die Systeme schreiben, die alles in eine Klasse hauen.
Eine große Klasse, eine Static, eine Main-Methode.
Da passiert alles drin. Super. Das ist dann,
das ist dann, wenn man Java-Objektorientierung eigentlich nicht
richtig verstanden hat
Für alles zuständig und hält 90 Prozent des Quertextes.
Oder Methoden, die mehrere Bildschirmseiten lang sind. Keine gute Idee.
Oder Klassen mit mehreren hundert Methoden. Auch keine gute Idee. Immer so,
das sind so üble Gerüche, wo man so sagt,
wenn da sowas auftaucht, dann, das ist wahrscheinlich die Kuison niedrig,
weil wenn eine Einheit sehr viele Aufgaben erfüllt,
erfüllt sie vermutlich zu viele Aufgaben.
Okay. Dann ein Hinweis für euch zum Vertiefen,
Solid-Prinzipien von Robert C. Martin, einfach zum Nachlesen,
dass es vieles von dem, was jetzt hier gesagt wurde,
nochmal anders aufgegriffen.
Anders spezialisiert, aber immer als Basis niedrige Kopplung,
hohe Korrision. Wenn man letztendlich immer damit erreichen.
Auf jeden Fall empfehlenswert, die nachzulesen. Das ist die
Zusammenfassung, innere Qualität eben halt auch Wartbarkeit, Portierbarkeit.
Wenn wir die innere Qualität eines Systems sehen,
dann ist die halt bestimmt durch den Klassenentwurf.
Wie kriegen wir einen guten Klassenentwurf? Es gibt einige Richtlinien
. Und was wir immer anstreben sollten,
ist eine hohe Korrision und eine niedrige Kopplung. Gut,
und da habe ich natürlich jetzt nochmal so ein bisschen Storesi dazu.
Wo ist es denn hier? Storesi? Nee, habe
ich doch. Dooresi habe ich noch gar nicht gestartet.
Eine kurze Frage. Nee, zwei habe ich noch,
glaube ich. Das können wir
noch hinkriegen
Ja. Okay, ich starte schon mal,
dann könnt ihr das in Ruhe lesen.
Welche der folgenden Aussagen ist am wenigsten falsch? Zum Entwurf.
Weil ihr wisst, es gibt kein richtig und falsch mehr.
Bei Entwürfen ist das nicht so ganz einfach. Also,
fünf Klassen, die sich alle gegenseitig benutzen, sind sehr lose gekoppelt.
Je weniger Methoden eine Klasse enthält, desto besser ist die strukturiert.
Durch das Einführen von Interfaces kann die Kopplung in einem System
reduziert werden. Ein vernünftiger Entwurf ist nur mithilfe von UML-Klassendiagramm
So, jetzt könnt ihr euch entscheiden,
welche davon die am wenigsten falsche ist.
Es gibt immerhin schon ein paar Stämmen dazu.
Möglicherweise eine relativ einfache Sache. Ah, so,
40 Leute sind bestimmt hier. Ja, sehr gut.
Gut, also Entscheidung jetzt. Ich beende,
wir gucken mal,
wie so
die Verteilung ist
Ja, gut. Wow, habe ich wahnsinnig gut erklärt.
Heute, also das ist natürlich die richtige Antwort.
Durch das Einführen von Interfaces kann das reduziert werden, die Kopplung.
Gut, das hier ist nochmal ganz lustig. Angenommen,
wir haben das Beobachter, Muster in einem System mit
einem Interface und einer abstrakten Klasse selbst gebaut.
Also nicht die Framework-Klassen verwendet. Und das auch an verschiedenen
Stellen eingesetzt. Wie sollten die beiden Typen dann heißen?
Beobachter und beobachtbar oder ob Server und ob Server will?
Nach den Sprachregeln, die wir hier gerade diskutiert haben
Das ist jetzt tatsächlich eine 50-50-Frage, ja,
total langweilig eigentlich. Das ist eher eine Diskussionsfrage dann.
So, haben wir hier noch 40 Stimmen, ja,
wir kriegen 40 Stimmen zusammen, ja, ja, ja.
Ja, toll. Gut. Ich beende,
wir gucken mal, wie so die Verteilung ist.
Ja, das habe ich mir gedacht. So, und
meine richtige Antwort ist die hier, Observer und Observable.
Kann mir einer sagen, warum ich das meine?
Nach meiner, also es ist zumindest konsistent mit meiner Begriffswelt
, ja
Teil nach dem, was die Empfehlung daraus geworden ist.
Schaut es euch, dass ihr die Macht auf ganze Verziehung
habt. Wir erscheinen, wird das möglich,
die Macht daran, dass ihr die Macht daran erscheint.
Ganz genau. Also er sagt das Richtige,
dieses Beobachten ist eine total technische Aspekt für Software-Systeme.
Und deswegen sollte man die Dinger auch ob Server und Observible nennen,
selbst in einer deutschen Fachlichkeit ist es einfach schlau,
die so zu nennen, einfach um klar zu machen,
da wird jetzt was Technisches modelliert, dieses Beobachter und Beobachtbar.
Es sei denn, Beobachter und Beobachtbar sind tatsächlich irgendwie fachlich motiviert,
aber in diesem Beispiel habe ich ja gerade gesagt,
dass Beobachter musste, für diesen technischen Zweck,
dass Dinge entkoppelt werden können, würde ich immer sagen,
mach's Englisch.
Das haben wir, glaube ich,
in unseren eigenen Systemen auch teilweise nicht eingehalten.
Okay, dann, wenn keine Fragen mehr sind,
dann machen wir Schluss für heute.