So, also jetzt bin ich wieder mal da.
Heute sprechen wir über Architekturstile und ich mache jetzt kein
Rätsel, weil wir sonst mit den Stilen nicht fertig werden.
Sie haben also schon den objektorientierten Entwurf gesehen, den
modularen Entwurf, bei dem es ja auf die Schnittstelle ankommt, dass
man Module austauschen kann, ihre Implementierung ohne das gesamte
System zu ändern.
Das Prinzip dahinter war das Geheimnisprinzip.
Da hatten Sie noch mal über was man mit Polymorphie und Beerbung
anstellen kann in der objektorientierten.
Das haben Sie alles schon gesehen.
Und jetzt betrachten wir sogenannte Architekturstile.
Architekturstile sind solche Dinge, die ein Gesamtsystem im Groben
strukturieren.
Und da gibt es einige bekannte Klassiker, die ich Ihnen jetzt zeigen
werde.
Ein ganz altes, klassisches Modell oder Architekturstil ist die
sogenannte abstrakte oder virtuelle Maschine.
Im Englisch natürlich abstrakt oder dafür ein T, ein R, virtual
machine.
Was soll das sein?
Nun ja, das ist eine programmierbare Maschine, die einzelne Befehle
hat.
Die aber meistens ein bisschen hochwertiger sind als die Befehle einer
nackten Maschine.
Also wenn Sie sich einen Pentium Prozessor ansehen mit seinem
Instruktionssatz, das ist keine virtuelle Maschine, sondern eine reale
Maschine.
Aber wenn ich mir jetzt höherwertige Dinge anschaue, zum Beispiel
fangen wir mit der Java virtuellen Maschine an, dann gibt mir die auch
Befehle, zum Beispiel den objektorientierten Aufruf, der ja heißt, ich
muss in Klassenhierarchien nach einem geeigneten Methode suchen.
Dynamisch.
Da steckt also wesentlich mehr drin als in einem ganz einfachen Call
and Link Befehl, der sich nur eine, der wohin springt und sich die
Rücksprungadresse merkt.
Das ist der Grundbefehl, der darin natürlich auch mitbenutzt wird.
Aber die virtuelle Maschine, der Java virtuelle Maschine, hat bereits
höherwertige oder funktionsreichere Grundbefehle.
Aber wir brauchen hier nicht stehen zu bleiben.
Sie können auch eine Programmiersprache als eine virtuelle Maschine
sehen.
Die virtuelle Maschine besteht jetzt aus den Operationen, die Sie in
der Programmiersprache haben, zum Beispiel Plus, Minus, Zuweisung, If,
While und so weiter.
Es ist klar, dass ich die implementieren muss mit den Grundbefehlen
der darunterliegenden Maschine oder eben einer Zwischenmaschine, wie
zum Beispiel der Java virtuellen Maschine.
Aber auch da sind die Befehle, die Sie jetzt zur Verfügung haben,
wesentlich besser, schöner zu benutzen als einzelne Befehle des
Prozessors.
Ein Betriebssystem, das zeige ich Ihnen noch genauer als Beispiel,
liefert auch eine virtuelle Maschine, nämlich die erweitert die
Hardware, die Sie haben mit zusätzlichen Diensten, zum Beispiel der
Verwaltung der Platte oder Kommunikationsdiensten oder einer
Kommandoschnittstelle oder einer grafischen Benutzerschnittstelle.
Anwendungskern GUI-Bibliotheken ist klar, da kann ich auch, natürlich
jetzt etwas eingeschränkter, da kann ich nicht mein beliebiges
Programm machen, sondern nur noch Bildchen.
Ein Anwendungskern besteht auch aus Grundbefehlen, den Sie zum
Beispiel aus der GUI grafischen Bibliothek aus ansteuern können.
Selbstverständlich, ich sage ja immer, wenn die Informatiker was
haben, dann wird sofort rekursiert.
Das kann ich natürlich jetzt auch machen.
Ich kann virtuelle Maschinen aufeinander stapeln.
Ich könnte mit einer realen virtuellen Maschine anfangen, darauf eine
java -virtuelle Maschine installieren und darauf einen Anwendungskern
installieren, darauf eine GUI-Schnittstelle installieren, die den
Anwendungskern benutzt, welche wiederum die java-virtuelle Maschine
benutzt, welche wiederum nach unten geht und die tatsächliche Hardware
benutzt.
Irgendwo muss es dann auf eine wirkliche Hardware laufen, denn sonst
bewegt sich nichts.
Wir wollen diese Stapelung der virtuellen Maschinen, die kann ich
natürlich auch als Graf auffassen, nicht nur linear aufeinander bauen,
sondern auch außen Abzweigungen haben.
Aber wir wollen dafür sorgen, dass sie zyklenfrei ist, denn die
Ausführung wird immer weiter unten geschehen und wenn wir da Zyklen
einbauen, dann geschieht auch wieder mal nichts.
Also eine abstrakte Maschine wird in der Regel von einem oder mehreren
Modulen, die java-virtuelle Maschine zum Beispiel bestimmt aus
mehreren oder Paketen implementiert, dabei werden die Softwarebefehle
und Objekte von den Schnittstellen dieser Module bereitgestellt.
Okay, das glaube ich verstehen wir.
Die darunter liegende andere Maschine, kann jetzt virtuell oder real
sein, muss dann ganz oder teilweise verdeckt werden, weil sie dann,
weil ein Benutzen von einer virtuellen Maschine plus den Befehlen der
unterliegenden virtuellen Maschine, weit unterliegenden virtuellen
Maschine zu Inkonsistenzen führen kann.
Also zum Beispiel, angenommen, Sie benutzen die java-virtuelle
Maschine, um einen Methodenaufruf zu machen.
Innerhalb dieses Methodenaufrufs benutzen Sie aber jetzt, sagen wir,
einen Pensionbefehl, um einen weiteren Methodenaufruf zu machen.
Der wird wahrscheinlich nicht den Aufrufsaktivationsrahmen, den Sie
brauchen, um einen Methodenaufruf aufzustellen, richtig aufsetzen,
sondern wird lediglich, was weiß ich, die Rücksprungadresse speichern
und sonst nichts tun.
Und das heißt natürlich, dass Sie an einer anderen Stelle mit diesem
händischen aufgerufenen Methode nicht die gleichen Funktionen
ausführen kann und mir einfach den Aufrufstapel durcheinander bringt.
Deswegen muss ich dann, wenn ich den java-virtuellen Maschinen
-Methodenaufruf benutze, darf ich nicht mehr den Hardware-Befehl für
den Aufruf dazwischen setzen, denn der bringt mir die ganze
Speicherorganisation meiner virtuellen Maschine durcheinander.
Natürlich ist jetzt die Frage, was soll ich da für Befehle wählen, die
schöneren, die tolleren und so weiter.
Das ist in der Tat keine einfache Geschichte.
Der Entwurf der virtuellen Maschine zum Beispiel für Java ist ziemlich
komplex, weil er auch zum Beispiel Sicherheitsaspekte berücksichtigen
muss.
Aber im Generellen sagt man, dass die Befehle, die man da zur
Verfügung stellt, möglichst allgemein benutzbar sein kann, in
möglichst vielen unterschiedlichen Programmen, die man damit schreiben
kann, nützlich sein sollten.
Man spricht auch manchmal, wenn man so eine virtuelle Maschine hat, wo
man vielleicht nicht sagt, dass es eine ganze virtuelle Maschine ist,
sondern lediglich eine kleinere Schnittstelle zur Verfügung stellt, da
spricht man auch von einer Application Programming Interface.
Aber auch das ist eigentlich eine virtuelle Maschine, denn ich kann
sie programmieren.
Anwendungsschnittstellen.
So, jetzt kommen Beispiele für abstrakte Maschinen.
Ich sagte schon, das Betriebssystem ist so eine abstrakte Maschine,
die hat sogar mehrere Ebenen.
Auf der untersten Ebene findet man in diesem Betriebssystem meist eine
Prozessverwaltung, da werden die einzelnen Prozessoren, die in einer
Rechner sind, zugewiesen an die verschiedenen Prozesse, die sie
ausgeführt haben wollen.
Sie haben in der Regel viel, viel mehr Prozesse, die auf Ausführung
warten, als sie Prozessoren haben und diese Zuteilung wird in der
Prozessverwaltung gemacht und das werden Sie sicher ganz genau
kennenlernen in der kommenden Vorlesung über Betriebssysteme.
Dann gibt es einen virtuellen Speicher.
Der virtuelle Speicher gibt Ihrem Programm, das Sie schreiben, die
Illusion eines großen Speicherraums, der sehr viel größer ist als
wahrscheinlich der Hauptspeicher Ihrem Rechner.
Vielleicht 100 Gigabyte oder so etwas und das haben Sie in einem PC
wahrscheinlich nicht.
Wie der virtuelle Speicher realisiert wird, ist immer wenn Sie auf
eine Adresse zugreifen, die außerhalb des verfügbaren Rahmens liegt,
in Ihrem Hauptspeicher, erfolgt eine Unterbrechung.
Das Betriebssystem springt ein und sagt, hoppla, hier kommt eine
Adresse, die ist nicht im Speicher.
Ich muss sie da in den Speicher holen und mache einen sogenannten
Seitenaustausch.
Das heißt, es sucht sich einen Block, eine Seite, etwa 4 Kilobyte in
dem kleinen Speicherraum im Rechner, sagt, die lagere ich jetzt aus
auf den Hintergrundspeicher, hol mir die für eine andere Seite herein,
weise die Adresse so zu, dass jetzt der Aufruf oder der Befehl, der
auf diese Adresse zugreift, richtig funktioniert und dann läuft das
Programm weiter.
Das heißt, es entsteht die Illusion eines sehr großen Speichers, was
natürlich die Programmierung sehr, sehr stark vereinfacht, weil sie
nicht dauernd mit dem Management des Hauptspeichers befasst sind.
Das war eine sehr, sehr wichtige Erfindung der virtuelle Speicher.
Dann gibt es die Datenhaltung auf dem Hintergrund, das kennen Sie, die
vielen Dateien und Verzeichnisse, die Sie auf Ihrer Platte haben.
Die Platte selbst kann eigentlich nicht viel, außer eben Bytes
speichern, Blöcke eigentlich von einigen hundert Bytes auf einmal
speichern und sie wiederholen, aber die Einteilung und Strukturierung
in Dateien und Verzeichnissen, das macht das Betriebssystem.
Dann gibt es die Kommunikationsschnittstelle, mit der Sie ans Internet
gehen, da sollte Ihnen klar sein, was da ist, schließlich bekommen Sie
oben drüber eine Kommandoschnittstelle die man als Informatiker schon
beherrschen muss.
Die meisten Endbenutzer allerdings haben gar keine Ahnung, dass es
eine Kommandosprache gibt, sondern benutzen grafische
Benutzoberflächen.
Auch das ist dann, sagen wir mal, die oberste Schicht in so einem
Betriebssystem.
Aber Sie haben damit einen Rechner, eine virtuelle Maschine, die sehr
viel mehr ausführen kann, als wenn Sie eine Maschine ohne
Betriebssystem hätten.
Eine Maschine ohne Betriebssystem ist so gut wie nicht benutzbar.
So mühsam ist es, mit so einer Maschine zu arbeiten.
Das Betriebssystem verdeckt übrigens auch gewisse privilegierte
Befehle, die zur Implementierung der virtuellen Maschinen notwendig
sind und das ist so kritisch, dass die Nichtnutzung dieser
privilegierten Befehle sogar zur Laufzeit überprüft wird, wenn Sie
einen solchen Befehl, solcher Befehl zum Beispiel, ist das direkte
Ansteuern der Platte, wo Sie sagen, ich will auf meiner Platte auf
Sektor X, Y und Z ein paar Bytes schreiben.
Das schreibe ich jetzt direkt.
Der Befehl, der das ausführen würde, den gibt es natürlich, in dieser
Maschine wird dann entweder, der könnte natürlich dazu führen, dass
Sie das ganze Dateisystem auf der Platte überschreiben, durcheinander
bringen, über Dateigrenzen hinweg schreiben, irgendwelche
Verzeichnisse kaputt machen oder so etwas.
Das ist sehr kritisch, dass das Dateisystem immer überlebt, dass das
Dateisystem auch den Absturz Ihres Rechners überlebt.
Sonst werden Sie sehr unzufrieden mit Ihrem Gerät.
Jedes Mal, wenn Sie es ausstecken, sind möglicherweise Daten weg.
Das wollen Sie nicht und daher sind diese Befehle privilegiert und
wenn Sie es schaffen, ein Sembler-Programm zu schreiben, in dem dieser
Befehl vorkäme, dann sagt das Betriebssystem, hoppla, das darfst du ja
gar nicht, unterbricht das Programm, stoppt es oder ignoriert einfach
den Befehl, sagt, der ist privilegiert, den sollte man hier nicht
nutzen.
Okay, also das ist ein kurzer Überblick, was ein Betriebssystem macht,
als ein Beispiel für eine virtuelle Maschine.
Gibt es da irgendwelche Fragen von Ihnen?
Wie gesagt, es gibt eine ganze Vorlesung dafür, da werden Sie das
alles noch ganz genau sehen.
Die java-virtuelle Maschine habe ich auch schon erwähnt, die
interpretiert sogenannten Bytecode.
Okay, der java-Übersetzer ist auch eine virtuelle Maschine, die
übersetzt zunächst mal auf Java-Bytecode, der dann interpretiert wird.
Der Java-Bytecode-Interpretierer, der verwirklicht die Java-Bytecode
-virtuelle Maschine.
Dabei werden auch Maschinenbefehle und Bytecode wieder verdeckt.
In ihrer Java-Programmiersprache sehen Sie ja nichts von dem Bytecode.
Und diese Verdeckung wird jetzt vom Übersetzer überprüft.
Natürlich kann die, ja gut, da kommt zu diesem Punkt kommen wir
gleich, ein Dokumentenformatierer könnte ich auch als eine ganz, ganz
einfache virtuelle Maschine betrachten.
Die kann nichts anderes als Randausgleich und Darstellung und
verschiedene Sätze und also Schriftsätze und Größen angeben und Fett
und Kursiv und unterstrichen und hochgestellt, was es da alles gibt.
Hat auch einen bestimmten Befehlssatz.
Der Befehlssatz ist gegeben durch Menüs in der Regel, aber es gibt
auch andere Dokumentenformatierer, zum Beispiel LaTeX.
Da hatte man tatsächlich in den Text, den man formatiert haben wollte,
Befehle eingesetzt.
Befehle gesagt, das hier ist eine Überschrift.
Setzen Sie gewissermaßen als Überschrift oder das hier ist eine
Aufzählung, nummeriert, nummeriert das Brücker ein, nummeriert durch
und so weiter.
Da geben Sie einzelne Befehle an, die werden tatsächlich von der LaTeX
- Übersetzer als Befehle interpretiert und ausgeführt, so dass ein
formatierter Text entsteht.
Beispiel, mein System zur Bearbeitung elektronischer Post bietet auch
Befehle an, die Sie ausführen können.
Die lösen Sie aus, indem Sie normalerweise auf der Schnittstelle, also
auf der grafischen Schnittstelle oder auch per Hand Befehle ausführen.
Sie bekommen dafür ordentliche Mailboxes und die Pufferung von langen
Nachrichten wird automatisch durchgeführt und so weiter.
Mit Makros haben Sie wahrscheinlich nichts zu tun gehabt.
Wer hat schon mal mit Makros gearbeitet?
Okay, doch schon einige.
Mit Makros kann man auch so etwas wie eine virtuelle Maschine bauen,
aber Makros sind ganz einfach.
Nämlich, sie führen nichts aus wie Befehle in der Java virtuellen
Maschine, sondern ersetzen nur Textzeichen mit anderen.
Zum Beispiel, wir können in C einen Makro definieren, der heißt Swap.
Den Damen können Sie natürlich selbst frei wählen, müssen nur dieses
Kreuz Define davor setzen.
Das Wort ist definiert als Temp ist gleich x, y, y ist gleich Temp.
Das ist ein Austauschbefehl.
Wenn Sie den, sagen wir, in Ihrem Programm so aufrufen, wird er
ersetzt durch diese Zeichenreihe, wobei die Parameter x, y textuell
ersetzt sind.
Nicht wertemäßig, sondern textuell.
Das heißt, Sie expandieren diesen Aufruf in Ihrem C-Programmtext mit
diesem Text.
Da fehlt übrigens die Definition, die Deklaration von Temp.
Möglicherweise funktioniert diese Makro gar nicht richtig, es sei
denn, Sie haben Temp richtig deklariert.
Also es ist kein Ausführen, sondern einfach expandieren eines Textes,
der dann später vom Übersetzer gelesen wird und erst umgesetzt wird in
Maschinencode.
Man hat diese Makros vor allen Dingen zuerst in den Assembler-Sprachen
benutzt, also in den niedrigen Maschinensprachen, weil man dort
oftmals sich wiederholende Befehlsfolgen abgeben musste, zum Beispiel
für den Methoden oder eher für den Funktions- oder Prozeduraufruf.
Und das hat man dann in Makros gepackt, sodass man nicht immer den
gleichen Befehlsatz immer wieder hinschreiben musste.
Aber Makros können diese Verdeckungsfunktion nicht bewerkstelligen.
Sie sagen einfach, hier ist Text, du sagst mir, dass Swap AB ersetzt
werden soll durch diese Zeichenfolge, mache ich einfach.
Was Sie da reinschreiben, ist dem Makro völlig egal.
Also ein Verdecken ist ja nicht möglich.
Daher ist es mit den Makros immer so eine Sache, Sie erleichtern die
Schreibweise ohne Zweifel, aber gestatten wir nicht irgendetwas der
darunterliegenden Maschine.
In diesem Fall wäre das die C-Programmiermaschine, also die C-
Programmiersprache zu verdecken, weil ich etwas Besseres habe, das
konsistent gehalten werden muss.
Ich soll erklären, was der Unterschied ist zwischen einem Makro und
einer Methode.
Also ich sage es noch mal, wenn Sie eine Methode hinschreiben, geben
Sie einzelne Befehle an.
Wenn auf diese Methode der Befehlszeiger kommt, auf die übersetzte
Methode natürlich, dann werden diese Befehle einzeln ausgeführt.
Ein Makro funktioniert anders.
Ein Makro sagt, hier ist eine Reihe von Befehlen, dann kommt ein
Makroaufruf und der Makro implantiert einfach an der Stelle Text,
expandiert Text.
Dann wird also diese Methode, die Sie geschrieben haben, mit diesem
extra Text versorgt zur Übersetzungszeit, nicht zur Laufzeit.
Sondern bekommt der Übersetzer also eine längere Methode, dass er Swap
durch diese Zeichenreihe setzt, Pramert ersetzt und so weiter.
Aber es heißt nicht, dass es ausgeführt wird, es sagt lediglich
textuell ersetzen.
Sodass ich jetzt, wenn ich das in expandierte Methode jetzt wieder
ausgeführt haben möchte, komme ich irgendwann mal an diese textuell
eingefügten Befehle und die werden dann ausgeführt.
Das ist eine reine textuelle Ersetzung, gewissermaßen eine Schablone,
die Sie an der Stelle einfügen, die dann später erst übersetzt werden
muss und dann erst ausgeführt wird.
Es sieht so aus wie eine Methode, funktioniert aber anders.
Dann Virtualisierung bei Dienstgebern im Internet, das sogenannte
Cloud Computing.
Da sind virtuelle Maschinen extrem wichtig geworden.
Wenn Sie also jetzt, Sie als Kunde könnten zum Beispiel sagen, ich
habe eine Anwendung, die läuft aber nur auf IBM Rechnern.
Dann können Sie sagen, ich miete einen IBM Rechner in der Cloud, einen
Cloud IBM Rechner.
Er muss aber gar nicht auf einem IBM Rechner laufen, sondern er könnte
auf einem virtualisierten Rechner laufen, der so tut, als wäre er ein
IBM Rechner mit seinem eigenen Befehlssatz.
Dieser Befehlssatz des IBM Rechners, der ganz anders ist als der
Pension Befehlssatz, wird komplett als virtuelle Maschine auf einem
anderen Rechner simuliert.
Der Kunde kann dann so hingehen und sagen, ich habe mein eigenes IBM
Betriebssystem, will das auf diesem virtuellen Rechner installieren
und darüber meine Anwendungen laufen lassen und vielleicht noch eine
Datenbank hinzu, die alle darauf annehmen, dass sie auf einer IBM
Maschine laufen.
Aber die Software-Virtualisierung dieser virtuellen Maschine ist so
geschickt gemacht, dass ich tatsächlich der, wie bei einer Java
virtuellen Maschine, ihr in diesem Falle keine Java Befehle gebe,
Befehle der virtuellen Maschinen von Java gebe, sondern Befehle der
IBM Prozessoren.
Es ist dann sogar möglich, pro echtem Rechner mehrere virtuelle
Maschinen zu laufen zu haben.
Die können sogar unterschiedlich sein.
Ich brauche dazu unterschiedliche virtuelle Maschinen-
implementierungen natürlich.
Wie wird eigentlich diese Virtualisierung geleistet?
Da gibt es eine Technik, die wird so gesagt, dass ich das einfach als
komplett durch Software ersetze.
Ich habe also einen Befehl, der heißt, addiere zwei Register und setze
das Ergebnis in ein drittes Register.
Das steht hier in meiner Befehlsfolge.
Ich habe eine Software, die liest die Befehle der Reihe nach und sagt,
okay, addieren heißt Register 1, Register 2, Register 3.
Da habe ich drei Variablen.
Dann mache ich das, was das Ergebnis ist.
Das allerdings ist eine virtuelle Maschine, die relativ langsam läuft,
weil jeder, aber auch wirklich jeder Maschinenbefehl jetzt plötzlich
erfordert, dass ich einen Methodenaufruf durchführe, einige
Instruktionen durchführe und dann wieder zurückkehre.
Wäre viel nicht.
Das heißt also, der ursprüngliche Addierbefehl in dem echten Rechner,
der vielleicht nur einen einzigen Zyklus erfordert, erfordert jetzt
plötzlich viele Zyklen Ausführung und damit wäre die Maschine langsam.
Daher gibt es eine andere Technik, die kommt aus dem Übersetzerbau,
die sagt, ja gut, ich habe eine Folge von Maschinenbefehlen, sagen
wir, für einen IBM Rechner, einen Power Prozessor oder wie der heißt.
Ich weiß aber, wie ich die Befehle einzeln übersetzen könnte in den
nativen Befehlscode meiner, was weiß ich, Intel Rechners.
Dadurch geht man her und nimmt diese Befehlsfolgen her, übersetzt sie
zur Laufzeit in native Befehlsfolgen, die den gleichen Effekt haben.
Das ist ziemlich diffizil, aber das kann man so machen.
Und natürlich ist es so, wenn Sie sich jetzt vorstellen, Sie haben
eine Schleife, in der kommt ein Block von Maschinenbefehlen vor, dann
übersetzen Sie den natürlich nicht nur einmal.
Beim ersten Mal des Betretens gehen Sie her und übersetzen den, sagen,
okay, hier ist der Befehlscode für meine Maschine und wenn ich hier in
diese Schleife reintrete, dann führe ich nicht mehr per Software die
einzelnen Befehle auf, sondern die übersetzte Version.
Und die ist natürlich rasend viel schneller als die
Softwareimplementierung.
Das gleiche gibt es in der Java virtuellen Maschine auf einem anderen
Ebenen, nämlich der auf dem Java Bytecode.
Den können Sie entweder, so wie er da ist, durch Software einfach
Schritt für Schritt ausführen lassen, interpretieren, kommt aus der
Sicht, ein Bytecode Befehl für einen Methodenaufruf und dazu gibt es
eine Implementierung, also eine andere Methode, die jetzt das
durchführt oder aber Sie können hergehen und den Compiler sagen zu
lassen, diese Stückchen Code habe ich aber schon ein paar mal
ausgeführt, wahrscheinlich muss ich es noch 200 mal ausführen.
Ich übersetze das jetzt gleich in den Objektcode der darunterliegenden
Maschine und habe jetzt eine vergleichsweise schnelle, gewissermaßen
blitzerartige Ausführung der Methode, die vorher ewig langsam durch
Softwareinterpretation durchgeführt werden musste.
Also das kennen wir jetzt, jetzt verstehen wir das.
Virtuelle Maschine, Abbildung, entweder indem ich eine
Softwareimplementierung habe, die sagt, jeder Befehl wird ausgeführt
durch eine eigens dafür gebaute Softwareroutine oder aber ich nehme
diesen Befehl oder auch Folgen davon und übersetze sofort in die
native, also die tatsächlichen Befehlssatz der unterliegenden, echten
Maschine.
So, die Virtualisierung hier ist natürlich wichtig, weil ein Cloud
-Anbieter möchte natürlich möglichst vielen Kunden zur Verfügung
stehen, aber nicht einen riesigen Maschinenpark für alle Varianten von
Maschinen, einen einzelnen Rechner pflegen und warten, sondern der
würde sagen, es ist doch viel geschickter, ich habe einen oder ein
Park von Rechnern, die alles können.
Wenn er sagt, ich will ein IBM, bekommt er einen IBM-Rechner,
simuliert.
Wenn er sagt, er möchte einen Intel-Rechner, vielleicht habe ich so
einen, dann kann er direkt ausführen.
Wenn nicht, dann virtualisiere ich das eben auf einem anderen Rechner.
Damit kann ich die Rechner selbst besser auslasten und habe weniger
Hardware zu pflegen, die es unter Umständen gar nicht mehr gibt.
Durch Virtualisierung kann ich Uralt-Software auf Uralt
-Betriebssystemen auch noch laufen lassen.
Und dann kann ich natürlich auch Lastschwankungen ausgleichen.
So, das war also die virtuelle Maschine, ein ganz ganz wichtiges
Konzept in der Software-Architektur.
Dann gibt es noch ein Konzept, das ist die Programmfamilie oder
schicker ausgedrückt die Software- Produktlinie.
Englisch natürlich Programmfamilie oder Software-Productline.
Was soll das sein?
Das ist eine Menge von Programmen, eigentlich von ganzen Systemen, die
erhebliche Anteile gemeinsam haben.
Zum Beispiel von Code, von Entwurf, von Anforderungen, von
Spezifikationen, sodass sie gewissermaßen mehrere Varianten dieser
Software bieten können für unterschiedliche Kundenwünsche, die sich
ein bisschen unterscheiden.
Zum Beispiel im Funktionsumfang oder in der Plattform, auf der sie
laufen, haben sie eine Linux- Variante oder eine Windows-Variante und
eine Apple-Variante und eine IBM was weiß ich Variante und so weiter.
Und sie wollen natürlich nicht immer die Software für alle diese
Plattformen neu schreiben, sondern sie sagen an bestimmten Stellen
muss ich ein paar Module ersetzen.
Wir haben eine änderungsunempfindliche Schnittstelle, kennen wir ja
schon.
Wenn ich deren Implementierung ersetze, zum Beispiel ein Dateisystem
anzusprechen, dann läuft das auch auf einer anderen Maschine.
Der Grund, warum man das so macht ist, dass man natürlich hofft, dass
in der Produktfamilie eben die Menge, die erhebliche Anteile gemeinsam
bleiben und nicht nur punktuell etwas ersetzen oder neu implementieren
muss.
Es ist also wesentlich kostengünstiger, ein neues Modell, eine neue
Variante zur Produktfamilie hinzuzufügen, als das Programm von vorne
neu zu schreiben.
Dann habe ich auch nicht so einen hohen Wartungsaufwand, denn der
gemeinsame Anteil muss nur bei einem Fehler, der auftritt zum
Beispiel, nur der Fehler nur einmal behoben werden, nicht in allen
Varianten erneut.
Okay, wir sparen uns also Kosten und sie kennen das wahrscheinlich
auch schon.
Da gibt es die Home-Version und dann gibt es die professionelle
Version und dann gibt es, was weiß ich, die Enterprise-Version und die
unterscheiden sich im Funktionsumfang.
Kostet natürlich auch unterschiedlich viel Geld, ist klar.
Und wenn die die Home-Version eben ausreicht für den Privatbenutzer,
dann ist das ja in Ordnung.
Aber die Enterprise-Version, die alles kann gewissermaßen, hat immer
noch große gemeinsame Teile mit der Home-Version.
Und von ökonomischen Entwicklung ist das natürlich die Produktfamilie
hier eine gute Idee.
Wir wollen die Gemeinsamkeiten ausnutzen und Sachen wiederverwenden
und das ist nicht nur Code, den wir wiederverwenden.
Es kann auch sein, dass ich Anforderungen wiederverwenden will.
Denn auch Anforderungen zu erstellen, ist ziemlich viel Arbeit.
Denken Sie, Sie haben tausende von Seiten in Anforderungen in großen
Systemen.
Da wollen Sie sagen, ja dieses Kapitel hier, das wollen wir komplett
übernehmen in die neue Version.
Die Variationspunkte nennt man die Stellen, an denen die
Produktfamilie oder die Produktlinie variiert werden kann.
Gewissermaßen, wo Sie ein anderes Getriebe, ein anderen Radio, einen
anderen Scheinwerfer, einen anderen Dachreling, Anhängerkupplung oder
sonst irgendetwas einpflanzen können.
Natürlich jetzt softwaremäßig gedacht.
So, wie unterscheiden sich unterschiedliche Hardware, Betriebssysteme?
Sie unterscheiden sich in Formate ein und Ausgabe.
Irgendeiner will XML eine Ausgabe haben, andere wollen nur Texte,
andere wollen nur Komma-separierte Listen und was weiß ich.
Und das machen Sie alles als spezielle Module, die diese Ausgaben nach
Wunsch formatieren.
Funktionsumfang hatten wir auch schon gesehen.
Home-Version, professionelle Version, Enterprise-Version.
Intern können Sie sich auch unterscheiden.
Es kann sein, dass Sie unterschiedliche Datenstrukturen an gewissen
Stellen brauchen.
Solche, die mehr Daten umfassen können, die aber dann einen größeren
Hauptspeicher brauchen, den sagen wir der Home-Benutzer nicht zur
Verfügung hat.
Unterschiedliche Betriebsmittel, zum Beispiel in Ihren
Betriebssystemen oder aber es gibt Unterschiede in der Häufigkeit von
Eingabedaten oder gewisser Ereignisse.
Also es kann sein, dass Sie in der Home-Version eben bestimmte
Funktionsteile nicht sehr häufig benutzen, weil die sehr speziell
sind, aber in der professionellen und Enterprise-Version kommen Sie
wesentlich häufiger vor.
Es gibt sie in allen dreien, aber in der professionellen Version ist
sie darauf getrimmt, dass sie sehr häufig benutzt ist, also
effizienter gemacht als in der Home-Version.
Ja, also könnte ich nicht eine Software bauen, die einfach alles kann,
also Home, professionell und Enterprise-Version, alles in einem?
In anderen Worten, jeder kriegt, der will die Enterprise-Version, ob
er alles davon braucht oder nicht, ist egal.
Kann man natürlich machen, erfordert aber, dass der entsprechende
Plattform des Benutzers zu Hause natürlich auch einen leistungsfähigen
Prozessor hat, sehr viel Hauptspeicher hat, ein riesen Plattenlaufwerk
hat, vielleicht Anschluss hat an ein Plattensilo, wo ja 20 Platten
laufen, das hat der Heimbenutzer nicht, also er kann das Zeug gar
nicht nutzen, um das Ganze dafür zu führen, dass die Software gar
nicht läuft.
Ich bräuchte jetzt aber einen Zugang zu irgendwas, das ihr Heimrechner
nicht hat und dann blockiert die ganze Geschichte.
Dann unterscheiden wir zwischen Allgemeinheit, bei der Programm,
zwischen Allgemeinheit, das heißt, dass ein System in vielen
Situationen ohne Änderung benutzt werden kann, alles kann
gewissermaßen, was man möchte oder ein Programm, das flexibel ist, das
einen gewissen Funktionsumfang hat, das aber für geänderte Situationen
leicht abgeändert werden kann.
Wir werden hauptsächlich darauf hin arbeiten, eine flexible Systeme zu
bauen, die erweiterungsfrei bleiben, weil wir in vielen Fällen einfach
nicht voraussehen können, was der Kunde später wissen, haben will.
Es kann sein, dass wir irgendetwas einbauen, einplanen, das den Kunden
dann völlig egal ist.
Und das sehen sie ja auch in der Software, die immer in Version 3 und
4 und so weiter ankommt, weil man nach und nach herausgekriegt hat,
was der Kunde eigentlich am liebsten haben wollte.
Daher brauchen wir einen änderungsfreundlichen Entwurf, nicht einen,
der alles mögliche, was in Zukunft erscheinen könnte, leisten muss.
Unterschied zwischen Allgemeinheit und Flexibilität.
So, jetzt kommen wir zu Architekturstilen.
Also das waren jetzt ganz generell Begriffe, die man jetzt nicht als
Architekturstil bezeichnen kann.
Die Programmfamilien, die Schichtenarchitektur und die virtuelle
Maschine.
Entschuldigung, Schichtenarchitektur kommen wir gleich.
So, die Architekturstile legen jetzt den Grobauffall eines Software
-Systems fest und da gibt es einige Klassiker, die Ihnen sicher gleich
auffallen werden.
Die Schichtenarchitektur, Client-Server, Partnernetze, Peer-to-Peer,
Datenablage vielleicht schon weniger, Model-View-Controller, das
könnte man auch benutzen.
Schauen wir uns mal die Dinge an.
Also das Einfachste und der Klassiker ist die Schichtenarchitektur.
Die Schichtenarchitektur sagt, ich baue mein System auf in mehreren
Schichten oder Ebenen, wobei eine Ebene die darunter liegende Ebene
aufrufen kann oder benutzen kann, aber nicht umgekehrt.
Ich kann nicht nach oben greifen, gewissermaßen.
Jede Schicht besteht aus einer Menge von Softwarekomponenten, können
Module sein, können Klassen sein, Objekte, können Pakete sein, ob
objektorientiert oder nicht objektorientiert, ist egal.
Wir brauchen lediglich eine wohldefinierte Schnittstelle, die diese
Schicht dann einer anderen Schicht, die darüber liegt, zur Verfügung
stellt.
Die Benutzrelation ist linear, sie geht von oben nach unten, darf auch
baumartig sein, darf sich aufspalten, aber ist wieder mal a-zyklisch.
A-zyklisch, damit wir nicht in die Petrolhecke geraten und alles
funktionieren muss, bevor wir irgendetwas ausprobieren können.
Wir wollen immer von unten her testen oder auch notfalls von oben.
Hier wäre so ein Bild dafür.
Wir haben die Schicht 0, die Schicht 1 und die Schicht 2.
Die Schicht 0 macht die Datenhaltung, da werden Daten gespeichert.
Irgendjemand sagt etwas?
Gibt es da eine Frage bei Ihnen?
Dann hier der eigentliche Anwendungskern und vielleicht drüber die
Benutzeroberfläche.
Das wären diese drei Schichten, klar aufgeteilt, wo was hingehört und
diese einzelnen Schichten können jetzt beliebig viele Komponenten
enthalten, die sich untereinander natürlich aufrufen und benutzen
dürfen.
Das ist kein Problem, aber die Benutzung hier geht immer von diese
Komponente kann alles, was in dieser Schicht vorkommt, benutzen und
die darunter liegende Schicht.
Die Frage ist jetzt bei der Schichtenarchitektur immer, ist das hier
auch erlaubt?
Darf ich von der obersten Schicht, Benutzeroberfläche bis runter in
die Datenhaltung greifen?
Das ist jetzt eher so ein religiöses Prinzip.
Es kann manchmal verboten sein, Leute wollen das wirklich nicht haben,
weil ich unter Umständen hier Konsistenzen verletze, wenn ich der GUI
-Schicht da unten in den Daten rumfummeln lasse, sollte lieber durch
die Anwendung hindurchgehen.
Oder aber sagen wir aus Effizienzgründen habe ich manche Funktionen,
die eigentlich unverändert hier oben benötigt werden, dann sollte ich
sie auch direkt benutzen können.
Wenn ich sie nämlich nicht direkt benutzen darf, wenn also dieser rote
Pfeil nicht erlaubt ist und da gibt es eine Funktion, die muss
eigentlich von der Anwendungsschicht gar nicht abgefangen werden.
Dann muss ich hier einen Stellvertreter einsetzen, der sagt, hier
mache ich einen Aufruf an Funktion F, dann brauche ich hier eine
Funktion F, die nichts weiter tut, also einen Aufruf hat in die untere
Schicht der Funktion F.
Sie einfach nur durchreicht und das kann manchmal ineffizient werden.
Es gibt zwei verschiedene Ausprägungen dafür, das normal ist schon
gesagt.
Die sogenannte intransparente Schichtenarchitektur, die sieht so aus,
wenn sie drei Schichten haben, dürfen sie von einer in die nächste
liegende greifen, aber nicht weiter.
Und das nach oben greifen, benutzen geht schon gleich gar nicht.
Das ist die intransparente und die transparente, können Sie
gewissermaßen durch die Schicht durchschauen, auf den unteren
Schichten, da ist das übergreifen hier erlaubt, aber das rückwärts
greifen natürlich nicht.
Also transparent, intransparente Schichtarchitektur haben wir jetzt
auch verstanden.
Gibt es Fragen dazu?
Wie gesagt, ein Klassiker, denn Sie kriegen eine übersichtliche
Struktur mit sauberen Abstraktionsebenen.
Sie können auch diese Schichten als virtuelle Maschinen auffassen.
Klar, die stellen Befehle zur Verfügung, die ich einer nächsten
virtuellen Maschine zur Verfügung stelle.
Sie haben keine allzu starken Einschränkungen, weil sie nämlich
innerhalb einer Schicht ist alles erlaubt, benutzen kann, also da so
kreuz und quer gehen, wie Sie es brauchen.
Und Sie haben Wiederverwendbarkeit.
Sie können eine Schicht, z.B.
die Datenhaltungsschicht, in einer anderen Anwendung wiederverwenden
oder Sie können eine Schicht ersetzen durch eine schnellere oder eine,
die auf eine bestimmte Maschine hin optimiert ist, abgestimmt ist auf
eine bestimmte Plattform und den Rest der Schichten beibehalten.
Das ist immer der Vorteil dieser virtuellen Maschinen, die man
natürlich austauschen kann.
Bei intransparenter Schichtung, das hatte ich schon erwähnt, kann es
zu Effizienzverlusten führen, wenn Sie immer nur weiterreichen müssen,
aber keinen Wert hinzufügen, anstelle direkt aufzurufen.
Das gleiche gilt übrigens für Fehlermeldungen.
Sie haben Schicht 1, gibt dann Schicht 2 weiter, gibt dann Schicht 3
weiter, gibt dann Schicht 4 weiter.
Unten tritt ein Fehler auf, da muss die Schicht drüber sagen, okay, es
kam ein Fehler, hier ist der Fehler-Code, sagte, kann auch nichts
damit machen, hier ist ein Fehler-Code und so weiter, werden die
Fehler -Codes wieder nach oben geleitet.
Das macht das Programmieren unschön, ja, ist auch unnötig.
Allerdings, wenn Sie mit Catch-and-Throw arbeiten, dann verschwindet
dieses Problem.
Dann müssen Sie nur sagen, an welcher Stelle Sie einen bestimmten
Fehler auf eine Ausnahme behandeln wollen und dann entfällt dieses
Problem schon ein bisschen.
Das ist sehr schön gelöst.
Das Durchreichen der Parameter natürlich von oben nach unten über
mehrere Stufen müsste ich bei der intransparenten Architektur aber
immer noch machen.
So, natürlich sollten Sie innerhalb einer Schicht auch nicht das
absolute Chaos verursachen.
Es gibt jetzt Abwandlungen, die heißen Drei-Schichten-Architektur und
Drei -Stufige-Architektur.
Die Drei-Schichten- Architektur, da hat man meistens einfach nur drei
Standardschichten.
Das ist die benutzte Schnittstelle, die Anwendungskern und ein
Datenbanksystem, genauso wie ich es Ihnen vorhin angedeutet habe.
Dann gibt es auch eine Drei-Stufige-Architektur, im englischen Three
-Tier -Architecture.
Das Tier ist also nicht das Tier, sondern auch wieder ein anderes Wort
für Schicht, Ebene oder so etwas, also Lage eigentlich.
Und das bedeutet, dass zumindest die Schichten auf mindestens zwei
unterschiedlichen Maschinen laufen.
Also es könnte zum Beispiel die Benutzerschicht auf einem
Klientenrechner laufen, aber der Anwendungskern und der Datenbank auf
einem Dienstgeber.
Dann spricht man von einem Three-Tier-Architecture.
Es müssen also nicht drei Maschinen sein, aber es müssen in diesem
Fall drei Lagen sein.
Okay, dann haben wir das bestanden.
Also hier wäre ein Beispiel einer vierstufigen Architektur.
Da haben Sie unten einen Kern, dann gibt es hier Grundfunktionen, dann
gibt es einen Anwendungskern 1 mit der zugehörigen
Benutzerschnittstelle, dann gibt es darauf noch einen anderen
Anwendungskern, der macht etwas ähnliches, könnte zu einer Familie
gehören.
Wir können also eine Produktlinie haben, eigentlich hier an der
Stelle.
Die benutzt auch die Grundfunktion und den Kern und sie ist
transparent, denn ich greife hier über diese Grundfunktionen
gelegentlich hinweg.
Also die Menge der Schichten ist hier keine Grenzen gesetzt.
In Betriebssystemen ist die Anzahl der Schichten so 10, 20.
Es gibt sehr viele Schichten übereinander.
Okay, hier ist noch ein Beispiel für eine weitere vier
Schichtenarchitektur bei Webdienstleistern, elektronischen Handeln.
Da haben Sie also einen Webbrowser, der hat nur die
Benutzerschnittstellenfunktion, der läuft auf Ihrem Klientenrechner.
Der Webserver liefert statische HTML-Seiten, da kann Sie nichts
eingeben und nichts verändern, es läuft nichts drauf, nur Text
gewissermaßen und Bilder.
Ein Anwendungsdienstgeber verwaltet Sitzungen, der sitzt oberhalb der
Datenbank, die die Daten verwaltet.
Der Anwendungsdienstgeber sagt, Sie sind jetzt da, melden Sie sich mal
an und melden Sie sich wieder ab und wenn Sie sich zwei Minuten nicht
rühren, dann beende ich die Sitzung oder so etwas.
Außerdem kann er noch dynamische HTML-Seiten erzeugen, wobei man auch
die dynamischen HTML-Seiten erzeugen eigentlich noch als eine weitere
Schicht nimmt, die parallel zu der statischen Schicht angeordnet sein
kann.
Obwohl ein Klassiker, immer noch gerne benutzt.
In den 70er-Jahren war das die Architektur, die man überall benutzt
hat, quasi die einzige, die man eigentlich kannte.
Heute kennt man es sehr viel mehr.
Betriebssysteme habe ich schon erwähnt, Protokolltürme bei der
Datenfernübertragung, das werden Sie auch in anderen Vorlesungen
hören, da gibt es Schichten über Schichten über Schichten, die
unterschiedliche Funktionen ausführen.
Informationssysteme sind Systeme, die meistens auf eine unterliegende
Datenbank aufsetzen.
Die bestehen oftmals auch in zwei Schichten, nämlich der Datenbank und
der Anwendung oder vielleicht der Anwendung mehrere Schichten.
Das gibt es sehr häufig.
Jetzt kommt noch eine kleine Variante für die Schichtenarchitektur und
zwar, die kann mit einer Fassade versehen werden.
Ich zeige Ihnen das am besten am Bild.
Nehmen wir an, wir haben eine Schichtenarchitektur mit zwei Schichten.
Oder sagen wir, das ist eine Schicht, das ist Schicht 2, 3 und 4.
Egal.
Und diese Schicht hat eine Vielzahl von Funktionen, die die einzelnen
Komponenten hier drin zur Verfügung stellen und sie möchten aber
nicht, dass die oberen Schichten jedes Detail aus dieser unteren
Schicht benutzen sollen.
Das heißt, sie möchten wieder mal was verdecken.
Gibt es da eine Frage?
Sie reden gerade mit ihrem Nachbarn.
Haben Sie eine Frage zur Schichtenarchitektur?
Nein?
Gut.
Da baut man eine sogenannte Fassade ein.
Man könnte auch sagen, die Fassade ist wieder eine spezielle Schicht
und die bereinigt die vielen Aufrufe, die hier möglich waren und gibt
nur noch wenige davon weiter.
Die Fassade macht nichts weiter als Aufrufe delegieren und wenn man
die Fassade benutzt, dann kann man nur das benutzen, was die Fassade
zur Verfügung stellt und nicht jedes Detail, was hier drin ist.
Was die Fassade auch noch gerne macht, ist, dass sie sagt, es gibt
bestimmte Befehlsfolgen aus dieser unteren Schicht, die immer in
Kombination auftauchen und die stelle ich dann also auch schon in
Kombination als einzelne Funktion zur Verfügung.
Also fast so wie ein Makro, dass ich nicht immer das gleiche immer
wieder hinschreiben muss.
Schreibe ich gleich eine Funktion, die die Kombination mir liefert.
Eine Art Bequemlichkeitsfunktion, die mehrere Dinge zusammenfasst, die
sowieso immer gemeinsam benutzt werden.
Das macht also die Fassade, die bereinigt und verschönert ein
bisschen.
Das macht die Benutzung der unteren Schicht bequem.
Klient-Dienstgeber, ja den habe ich schon erwähnt.
Das ist eigentlich nur eine Zweischichtenarchitektur oder, wenn man es
genau nimmt, eine Two-Tier-Architektur.
Da gibt es einen Klienten, der fragt normalerweise über das Internet,
einen Dienstgeber und ruft diese Dienste auf.
Dazu gibt es spezielle Protokolle, denn ich kann ja nicht wirklich
einen Aufruf an ein entferntes Betriebssystem machen.
Das kann ich nur auf meinem eigenen Rechner, sondern ich muss
natürlich einen Aufruf, der hier drin vorkommt, immer umsetzen in eine
Kommunikation, wo ich ein Paket schicke, das sagt, ich möchte
folgenden Dienst aufgerufen haben mit den folgenden Parameter.
Und hier ist ein Empfänger, der sagt, okay, gib das Paket her.
Ich setze den Aufruf schon zusammen, schreibe das in Variablen rein
und mache dann den gewünschten Aufruf für dich.
Selbstverständlich müssen auch in diesem Falle der Klient die
Schnittstelle des Dienstgebers kennen.
Mehr ist eigentlich gar nicht mehr zu sagen, jedenfalls nicht in
dieser Vorlesung.
Selbstverständlich ist die Kommunikationsschnittstelle hier wichtig,
aber die will ich hier in dieser Vorlesung nicht besprechen.
Vieles davon ist auch automatisch heutzutage umgesetzt, so dass wir
eigentlich hier nur die Dienste anbieten als Funktionen und hier einen
Aufruf machen, als wäre dieser Dienst lokal und die dazwischen
liegende Kommunikation wird automatisch erzeugt.
Das ist sehr praktisch.
Datenbanksysteme sind das oft benutzt, ein Frontend gibt ihnen die
Benutzoberfläche, als Backend der Datenbank, Zugriff und die
Manipulation.
Der Dienstgeber hat also die Funktionen Datenverwaltung,
Datenintegrität, Sicherung, Backup und so weiter, Sicherheit zu
leisten und Klient und Dienstgeber laufen in der Regel auf
verschiedenen Rechnern, aber wenn es sein muss, laufen die auf den
gleichen Rechnern.
Dann habe ich halt ein Dienstgeberlokal installiert und kann ihn auch
dann effizienter ansprechen.
So, zum Beispiel der FTP Server, ein FTP Server.
FTP heißt File Transfer Protocol, damit werden Daten übertragen, wird
in einem Rechner explizit aufgerufen, ohne dass sie es merken.
Sie können aber in ihrem Browser auch oben statt HTTP FTP
hinschreiben, dann wird das File Transfer Protocol benutzt.
Die entsprechende URL sieht dann eben nicht wie HTTP aus, sondern wie
FTP und da gibt es ein FTP Programm, das das versteht, das initiiert
das Übertragen einer Datei.
Der Dienstgeber reagiert auf die Klientenanfragen.
Die Klientenanfragen können entweder sagen, schick mir eine Datei oder
ich schicke dir die Datei und du speicherst sie für andere.
Jetzt zu den Partnernetzen, englisch Peer-to-Peer.
Was heißt Peer?
Peer heißt der gleichgestellte Gleichaltrige.
Sie sind Peers untereinander.
Peer Pressure haben sie vielleicht schon gehört, das heißt, wir
Gleichaltrige in der Klasse werden sie gezwungen, irgendwas zu tun,
was sie eigentlich gar nicht wollen.
Da ist jetzt die Idee, die Bezeichnung des Partners ist ja recht
treffend, denn jetzt gibt es nicht mehr einen Unterschied zwischen
Klient und Dienstgeber, sondern alle Partner sind gleichwertig.
Das heißt, sie übernehmen Klientenfunktionen als auch
Dienstgeberfunktionen.
Das heißt also, so ein Partner bietet Dienste an, kann aber auch
Dienste anfordern von einem anderen Partner.
Deswegen diese Assoziation hier.
Jeder Partner kann sowohl Anbieter als auch Anforderer sein in so
einem Netz.
Das heißt, der Partner selbst könnte eigentlich, könnte man sich so
vorstellen, dass es eine Mehrfachvererbung gibt der Klienten und der
Dienstgeberfunktion.
Besser ist, glaube ich, dieses Bild.
Der Klient-Dienstgeber sieht so aus, dass sie hier dazwischen einen
Dienstgeber haben, mehrere wenn sie wollen und die einzelnen Klienten
greifen auf diesen Dienstgeber über das Internet zu.
Beim Partnernetz gibt es keinen Dienstgeber mehr, sondern die Partner
können sich gegenseitig fragen, wenn sie eine Anforderung brauchen,
die sie selbst nicht erfüllen können.
In so einem Fall stellt sich natürlich die Frage und wo sind jetzt die
Daten?
In diesem Fall wussten wir genau, wo die Daten liegen, nämlich beim
Dienstgeber.
Im Partnernetz sind die Daten auf den einzelnen Rechner verteilt.
Das heißt, sie brauchen jetzt eine Möglichkeit, dass sie sie finden.
Sie brauchen also einen Lokationsdienst, der sagt, wo ist denn das
Ding heute?
Wer hat denn das?
Zweitens sind die Partner unzuverlässig.
Die Partner können mal abgeschaltet sein.
Sie sind in der Vorlesung, sind jetzt nicht gerade im Partnernetz
eingebunden und heißt das, dass die anderen Leute diese jetzt gerade
diese Daten nicht haben können?
Nein, muss es nicht heißen, wenn es noch einen anderen gibt, der eine
Kopie hat.
Das heißt, in diesem Partnernetz müssen sie auch noch Kopien halten.
Sofern man Kopien hat, muss man wieder darum sorgen, dass die Kopien
konsistent sind.
Das ist immer die Geschichte.
Sie können natürlich gerne Sachen verteilen, aber dann müssen sie sich
die Stelle fragen, wo ist das Zeug und wer sorgt für die notwendige
Zuverlässigkeit und Konsistenz?
Wenn ich also Duplikate habe und ich aktualisiere das Duplikat, muss
ich natürlich alle Duplikate finden können.
Okay, also Rollensymmetrie haben wir jetzt.
Jeder ist sowohl Klient als auch Dienstgeber.
Dezentralisierung.
Es gibt keinen zentralen Knoten, der alles enthält, der die zentrale
Datenbasis ist.
Sie hat ja auch Nachteile, wenn die nämlich ausfällt, ist alles weg.
Jeder Partner kennt in der Regel nicht alle.
Hier habe ich Verbindungen zu allen hingeschrieben.
Naja, das geht, weil ich hier nur sechs habe.
Wenn sie aber 2000 haben, dann wäre das ein Netzwerk,
Verbindungsnetzwerk, das sie auch nicht pflegen wollten.
Sie wollen also eigentlich nur eine Untermenge der anderen möglichen
Partner kennen, die sie anfragen können und das ist ein nächstes
Problem.
Wie wähle ich das aus?
Das werde ich jetzt aber nicht erklären, nur eine Andeutung, das macht
man über Hash-Funktionen.
Sie nehmen also ein Datenobjekt, das sie haben wollen, dafür gibt es
einen Bezeichner, den Bezeichner schicken sie durch eine Hash-Funktion
und die Hash-Funktion sagt ihnen, welcher andere Knoten das für sie
haben könnte.
Hash-Funktionen sind natürlich auch ungenau und wenn der andere, den
sie mit Hash-Funktionen erreicht haben, sagt, kenne ich leider nicht,
aber ich kenne noch andere und ich frage mal die für sie.
Dann werden sie gewissermaßen weitergeleitet.
Das muss sich dann alles regeln.
Also das Partnernetz wird schon ein bisschen komplizierter als das
Client -Dienstgebernetz.
Wir haben jetzt eine Interaktion aus den verschiedenen Partnern, die
ihnen den Gesamtdatenraum dann zur Verfügung stellen.
So, Autonomie, die einzelnen Partner können ihre Entscheidungen
autonom verhalten.
Sie verhalten sich autonom, insbesondere können sie sich abschalten,
wieder zuschalten, müssen dann aktualisiert werden.
Partner sind unzuverlässig, das habe ich schon.
Redundanz ist erforderlich wegen Unzuverlässigkeit.
Gibt es natürlich jede Menge, BitTorrent zum Beispiel, können sie
sofort einklinken, entsprechende Software installieren und dann sind
sie im BitTorrent-Netzwerk.
Netzwerkebene gibt es TCP, IP, da werden auch unterschiedliche Rechner
in der Netzwerker-Architektur selbst benutzt, so wie sie gerade von
der gegenwärtigen Lastsituation gelenkt sind.
Also gibt es schon einige.
Server Peers und dann letztendlich die Klienten, die sich auch als
Peer anwenden können.
Wenn Sie selbst nur als Klient auftreten, nur Daten holen wollen, aber
keinem zur Verfügung stellen wollen, ist klar, dann gehören Sie nicht
zu einem Peer-to-Peer-Netz.
Aber da gibt es offenbar auch zuverlässige Partner und weniger
zuverlässige Partner.
Klar, da kann man sich mehrere Stufen ausdenken von Zuverlässigkeit.
Okay, schauen wir mal.
Datenablage, das ist auch einfach nur eine Zweischichten-Architektur
oder eine Klient-Dienstgeber-Architektur, aber man benutzt diesen
Begriff manchmal, wenn es sehr stark auf die Daten ankommt.
Es gibt eben eine Datenablage, da können Sie Daten erzeugen,
hineinspeichern, wiederholen, suchen und so weiter und
unterschiedliche Subsysteme, die gleichzeitig auf die Datenablage
zugreifen, entweder lokal oder über das Internet.
Wenn mehrere darauf zugreifen, auf diese Datenablage, dann ist es
natürlich wichtig, dass sie Konsistenz erhalten.
Die Inkonsistenz kann entstehen, wenn mehrere gleichzeitig Daten in
der Datenablage verändern wollen und zwar gleich mehrere.
Also angenommen, nehmen wir das Beispiel eines
Sitzplatzreservierungssystems bei den Fluglinien her.
Da wollen Sie nicht, dass während Sie einen Sitzplatz reservieren,
dieser Sitzplatz bereits von jemand anderem reserviert wird.
Das wollen Sie vermeiden, sonst landen da plötzlich zwei Leute und
wollen sich auf den gleichen Platz setzen.
Wenn aber mehrere Reservierungsläufe gleichzeitig sind, kann das
durchaus, könnte das durchaus passieren.
Das heißt, wir müssen einen Synchronisationsmechanismus einbauen.
Diesen Synchronisationsmechanismus kennt man bei den, das ist ein
anderes Beispiel, bei den Datenbanken unter dem Begriff
Transaktionsmanager.
Ein Transaktionsmanager sorgt dafür, dass es eine Synchronisation
gibt, die folgendermaßen aussieht.
Sie erlauben Parallelzugriffe, aber für jeden Benutzer sieht es so
aus, als wäre seine Transaktion sequenziell durchgelaufen, vor einer
oder nach einer anderen.
Sodass Sie konzeptionell nicht an den gleichen Daten modifizieren.
Das hat den großen Vorteil, dass, sagen wir mal wieder, das Dienst des
Sitzplatzreservierungssystems, wenn ich vorne in der ersten Klasse
etwas reserviere und dann hinten in der Economy-Klasse auch etwas
reserviere, dann könnten diese beiden Transaktionen gleichzeitig
laufen, denn sie werden nie die gleichen Sitze benutzen.
Wenn ich aber zwei gleichzeitig in der Economy-Klasse laufen habe,
dann will ich sicher gehen, dass sie nicht den gleichen Platz zweifach
reservieren.
Und in diesem Falle muss ich sie sequenzialisieren, serialisieren,
also hintereinander garantieren, dass sie hintereinander laufen.
Aber die beiden 1.
Klasse und Economy-Klasse können gleichzeitig laufen.
Dieses Transaktionskonzept sorgt dafür, dass es so aussieht, als würde
ich meine Transaktion, selbst wenn ich drei Sitzeplätze reserviere,
auf einmal komplett durchlaufe oder eben versage und nichts passiert
ist, weil ich in Konflikt geraten bin mit einem anderen.
Dazu gibt es Vorlesungen, die das erklären, wie dieses
Transaktionsmechanismen funktionieren.
Da gibt es jede Menge an Literatur und ist in Datenbanken heute sehr
gut entwickelt.
Dazu müssen Sie aber auch eine Spezialvorlesung hören, um das zu
sehen, wie Transaktionen funktionieren.
Es gibt seit neuerem auch diese Transaktionen in Datenbanksystemen,
die arbeiten natürlich alle mit permanenten Datenablagen, das heißt
mit Plattenlaufwerken, damit die Daten nicht flüchtig sind.
Es gibt jetzt eine neuere Entwicklung, die spricht auch von
Transaktionen im Hauptspeicher, gerade für Mehrkernrechner.
Da hat man jetzt auch ein Transaktionskonzept, das läuft sogar im
Hauptspeicher eines einzelnen Rechners ab und das können Sie zum
Beispiel bei mir in der höheren Vorlesung im Masterstudium dann hören,
wie so ein Transaktionskonzept funktioniert.
In der Vorlesung Parallelrechner und Rechnerbündel.
Okay, so hier ist auch ein Beispiel für eine Datenablage.
Das ist jetzt keine dezentrale Datenablage, sondern eine, die in ihrem
eigenen Rechner läuft und zwar jedes Mal, wenn Sie einen Übersetzer
benutzen.
Der Übersetzer hat also mehrere Komponenten, zum Beispiel die
Syntaxanalyse, die lexikalische Analyse, die semantische Analyse, den
Optimierer und den Coderzeuger.
Das sind so die wichtigsten Komponenten.
Die lexikalische Analyse zum Beispiel identifiziert die einzelnen
Bezeichner und die einzelnen Ziffern, die einzelnen Symbole,
Zuweisungen, Gleichheit, kleiner gleich, größer gleich,
Schlüsselwörter.
Die werden in der lexikalischen Analyse identifiziert und nach
sogenannten Tokens weitergegeben, die nur einen einzelnen Code
darstellen.
Während die Syntaxanalyse sorgt dafür, dass, sagen wir, eine
Klassendeklaration in allen Bauteilen zusammenhängend stimmt und dass
eine Wahlschleife richtig formatiert ist, mit Bedingungen und
geschweiften Klammern und Anweisungsfolge und so fort.
Das macht zum Beispiel die Syntaxanalyse.
Die semantische Analyse sagt, ob eine Zuweisung zulässig ist zum
Beispiel.
Können Sie ein Integer auf einen Long zuweisen?
Können Sie ein Long auf ein Integer zuweisen?
Können Sie ein Objekt auf ein bestimmtes Klassenobjekt zuweisen?
Die Antwort ist nein und das überprüft also die semantische Analyse.
Optimiert erzeugt Code.
Und da gibt es aber eine zentrale Ablage, die fast alle diese Phasen
brauchen, nämlich den Strukturbaum.
Der Strukturbaum des Programmes, der wird als Syntaxbaum, kennen Sie
aus den Grundbegriffen der Informatik, im Rechner dargestellt.
Der wird modifiziert, abgesucht, überprüft auf Korrektheit und eine
sogenannte Symboltabelle oder Entschlüsselungstabelle, die sagt mir
für jeden Code, was das für Bezeichner war.
Und diese Information, diese Ablage, wird eigentlich, wenn Sie dann
Code erzeugen, an das Programm irgendwo angehängt, sodass diese
Entschlüsselung hier noch weiterhin möglich ist.
Für was?
Für den Debugger und für den Struktureditor, falls es den gibt.
Ein Debugger ist ja ziemlich schwer, wenn Sie ein übersetztes Programm
haben.
Das enthält ja nur noch einzelne Befehle.
Was haben die denn?
Wo entstand denn das?
Aus welcher Anweisung in meinem Quellcode entstand denn das?
Diese Übersetzung, Querverweise und so weiter, stecken auch in dieser
Symboltabelle und der Source Debugger kann sich darauf beziehen.
Aber Sie sehen hier, wir haben eine Ablage mit Informationen, die
viele Komponenten benötigen.
Ein Struktureditor ist einer, der die Syntax ihrer Programmiersprache
kennt und nur erlaubt, dass sie syntaktisch richtiges Programm
schreiben können.
Okay, das habe ich eigentlich alles erklärt.
Subversion SVN ist auch so etwas.
Das ist auch so eine Datenablage.
Da sind zum Beispiel alle unsere Vorlesungsunterlagen drin.
Ich habe heute gerade gesehen, wir sind jetzt bei Subversion
Versionsnummer 11.500 oder so etwas.
Für diese Vorlesung und noch ein paar mehr.
Model-View-Controller MVC ist jetzt etwas ganz anderes.
Eigentlich ein kleinerer Architekturstil.
Das zeige ich Ihnen aber, jetzt kommt eine textuelle Erklärung, die
können Sie nachher noch mal lesen.
Ich gebe es Ihnen per Wort.
Da haben Sie folgende drei Komponenten.
Sie haben ein Modell, eine Sicht oder eine Präsentation und eine
Steuerungskomponente, genannt Controller.
Die Idee ist folgendes, dass hier im Modell die Daten gehalten werden.
Die Präsentation oder View hier gibt Ihnen ein Abbild dieses Modells,
zeigt Ihnen den Inhalt dieses Modells an, entweder vollständig oder
nur ein Ausschnitt.
Wenn Sie einen Ausschnitt haben, dann haben Sie einen Rollbalken, dann
können Sie irgendwie über diese Daten drüber wandern.
Also stellen Sie sich vor, als Beispiel in diesem Modell haben Sie
eine große Tabelle, fünf Spalten, 3000 Zeilen, alphabetisch irgendwie
organisiert und die Sicht zeigt Ihnen auf Ihrem Bildschirm ein
Tabellenbild.
Das können Sie vergrößern und verkleinern und miniaturisieren, können
darin herumfahren.
Dazu gibt es noch einen Controller, der steuert jetzt die
Benutzereingaben.
Der könnte zum Beispiel veranlassen, dass wenn das Modell in einem
bestimmten Zustand ist, dass bestimmte Operationen erlaubt sind oder
nicht erlaubt sind, indem man die Knöpfe, mit denen Sie diese
Änderungen verursachen, also aktiv schaltet oder ausgraut.
Das heißt, Sie können sie nicht mehr betätigen.
Das macht zum Beispiel der Controller.
Warum macht man das so?
Warum nicht einfach ein Modell und die Anzeige dazu und der
Controller, den kriegen wir auch noch eingebaut.
Also einfach alles zusammen in eine Klasse reinstecken.
Naja, das hat einen Nachteil.
In vielen Fällen ist es notwendig, dass Sie für dieses Modell nicht
nur eine Ansicht bekommen, sondern mehrere.
Sie wollen mehrere Fenster öffnen und das tun Sie täglich.
Sie merken das noch nicht mehr, wenn Sie Ihren Internetbrowser
betätigen.
Wie viele Fenster haben Sie denn offen?
Wie viele Tabs haben Sie denn offen eigentlich?
Sie haben mehrere Sichten.
In diesem Falle nicht auf das Gleiche, aber vielleicht auch auf das
Gleiche.
Das heißt also, in der Regel wollen Sie mehrere Sichten haben, unter
Umständen sogar Sichten, die sich optisch unterscheiden.
Eine Miniaturansicht, eine große Ansicht, eine detaillierte Ansicht.
Deswegen wollen Sie die Dinger trennen, dass Sie die Sichten
hinzuschalten können und wieder abschalten können, so wie Sie sie
brauchen.
Die Fenster öffnen und schließen auf die gleichen Daten.
Wir werden später noch genauer sehen, wie wir die Kommunikation
zwischen Modell und Sicht oder Präsentation organisieren.
Irgendwie störend hier, Leute, ihr redet zu laut.
Ich verliere da immer den Faden.
Wo war ich jetzt?
Gehen wir nochmal zurück.
Die Benutzerschnittstelle könnte neu implementiert werden, ohne die
Darstellung der Datenobjekte zu ändern.
Das Modell, die Datenobjekte könnten neu organisiert werden, ohne die
Benutzerschnittstelle zu ändern.
Sie wollen die beiden unabhängig voneinander ändern und das geht mit
dem MVC ganz gut.
Zur Steuerung habe ich jetzt nicht besonders viel gesagt, aber ist
zuständig für die Benutzerinteraktion.
Man kann den Controller auch weglassen und nur Model und View
benutzen.
Dann spricht man von einem anderen Muster, nämlich dem anderen Stil.
Das ist das Beobachtermuster.
Man sagt einfach, die Präsentation oder die Sicht beobachtet das
Modell und muss immer aktualisiert werden, wenn sich das Modell
ändert.
Das werden wir uns noch genauer ansehen.
Es gibt auch eine optionale Verbindung zwischen View und Controller.
Das können Sie dann nochmal genauer studieren.
Ich könnte also zum Beispiel mit MVC hergehen und sagen, das Modell
kann ich wiederverwenden auf einer anderen Plattform, zum Beispiel von
Windows auf Linux.
Die Benutzerschnittstelle muss ich wahrscheinlich neu implementieren,
es sei denn, ich habe schon eine portable Benutzerschnittstelle
implementiert.
Dann könnte ich die Benutzerschnittstelle, die Präsentation auch
übertragen, aber oft ist das eben gerade nicht der Fall.
Aber das Modell brauche ich einfach neu zu übersetzen und dann läuft
es auch auf Linux wunderbar.
Das könnte ich auch nicht, wenn ich alles in eine Klasse stopfen
würde.
Dann bräuchte ich plötzlich eine Klasse, die hat eine Linux-
Anwendungs -Steuerungs-Funktionen-Methoden, was der Teufel.
Das ist dann extrem kompliziert.
Diese Trennung ist sehr praktisch.
Also eigentlich haben Sie hier keine Schichtenarchitektur mehr, weil
Sie hier gegenseitige Abhängigkeit haben.
Man kann es noch als Schichtenarchitektur sehen, nämlich zwischen
diesen beiden ist definitiv eine Schichtenarchitektur vorhanden.
Das Modell kümmert sich nicht um die Sicht.
Das Modell soll keinesfalls die Sicht irgendwie was rum modellieren,
sondern die Sicht soll sich die Daten holen und die Anzeigen fertig.
Das ist ein typisches Zwei-Schichten-Modell.
Was es verhindert, dass wir zwei Schichten haben, ist eben diese
Kreisverbindung.
So ist es halt.
Es ist nicht immer alles ideal.
Eine interessante Frage.
Noch Fragen?
Okay, jetzt kommt ein ganz einfaches Muster.
Das Pipeline-Muster oder auch das Fließband-Muster.
Das gibt es auch in sehr vielen Stellen, zum Beispiel bei
Videoverarbeitung, Videoströme, die laufen alle durch Fließbänder
hindurch.
Da ist es so, dass sie mehrere Verarbeitungsstufen haben
hintereinander.
Auch Übertragungsstufen können dazugehören, Verarbeitung- oder
Übertragungsstufen.
Die haben ihren eigenen Prozess, also ihr eigenes Programm.
Ein eigenes komplettes Programm führt also Stufe 1 auf und ein
zweites, völlig unabhängiges davon, führt die Stufe 2 aus und so fort.
Das ist der große Unterschied zwischen dem, was wir bis jetzt hatten.
Bis jetzt hatten wir immer von einzelnen Prozessen gesprochen.
Beim Pipeline-Verfahren haben wir das erste Mal eine echt parallele
Anwendung.
Jede Stufe hat sein eigenes Programm, seinen eigenen Buffetzähler,
seinen eigenen Prozess.
Jede Stufe empfängt von der vorhergegangenen Stufe die Daten,
verarbeitet sie, schickt sie weiter.
Um das wirklich gut funktionieren zu lassen, brauchen wir zwischen den
Stufen Puffer.
Diese Puffer nehmen die Daten auf, bis die folgende Stufe soweit ist,
die Daten abzunehmen, um Laufzeitunterschiede in den Stufen ein
bisschen auszugleichen.
Es kann also sein, dass die Stufe 2 gerade ein Stück Bild bekommen
hat, das sehr lange dauert, um es zu verarbeiten, zu verarbeiten.
Dann stauen sich hier ein paar weitere Bilder in einer Videofolge in
diesem Puffer.
Wenn Sie einen Parallelrechner haben, was wir heute in der Regel
haben, dann ist das überhaupt kein Problem, das ausführen zu können.
Aber man kann es auch auf einem Einzelrechner ausführen, indem man
jede Stufe eine Weile laufen lässt und dann eine andere Stufe laufen
lässt.
Ganz normaler Prozesswechsel im Betriebssystem.
Da sagt ein Prozessor in Prozesse, die muss ich jetzt abwechselnd auf
dem Prozessor laufen lassen.
Dazu gebe ich jedem ein bestimmtes Zeitquantum oder bis er sagt, ich
brauche jetzt eine Eingabe und es ist keine da.
Und dann läuft ein anderer.
Das Verarbeitungsprinzip sieht etwas so aus, ein völlig anderes Bild.
Eigentlich sollte ich das so machen.
Also das sind die Eingaben, die nach und nach ankommen.
Das ist nicht schwer.
Die erste Stufe bekommt in Zeit 1, natürlich A1, Zeitstufe 2, A2 und
so fort.
Die zweite Stufe bekommt sie verzögert.
Die dritte Stufe um drei Schritte verzögert, die vierte Stufe um vier
Zeitabschnitte, drei Abschnitte eigentlich verzögert.
Das ist alles, was das Bild soll.
Natürlich ist A1 dann schon verändert worden von der Stufe A1, also
müsste da A1 Strich dran stehen, da müsste A1 Zweistrich und so weiter
dran stehen.
Aber Sie sehen, dass ich jetzt zum Beispiel hier an dieser Stelle das
Fließband voll in Aktion habe, alle vier Prozesse arbeiten.
Der an A4, der an A3, der an A2 und der an A1.
Wenn das Ding aber dann gewissermaßen an Ense kommt, dann sehen Sie,
hier laufen noch alle Stufen.
Hier hat die erste Stufe nichts mehr, haben die ersten zwei Stufen
nichts mehr, hier hat die ersten drei Stufen nichts mehr.
Und schließlich läuft die Pipeline aus und natürlich läuft die letzte
Stufe am längsten.
Sie startet aber auch als letzte.
Pipelines gibt es auch schon Ewigkeiten.
Eigentlich ist das auch ein Klassiker.
Das ist zum Beispiel eine Pipeline, die können Sie sofort ausführen in
der Commanderzeile.
Das sind nämlich vier stufige Pipeline aus PS, dann gibt er den
Prozesszustand, gibt mir alle Prozesse aus, aus einer langen Liste.
Dann mit GREP, das ist ein Mustersucher, ein Befehl, mit dem sagen,
ich möchte jetzt alle Zeilen haben, mit denen Hans drin steht.
Dann kriegen Sie eine reduzierte Liste.
Dann schicken Sie es durch die Sortierstufe durch, die sortiert die
alle nach der ersten Spalte.
Können Sie aber auch angeben als Parameter, welche Spalte Sie benutzen
wollen.
Und schließlich lässt es, es gibt Ihnen die Ausgabe immer in
Bildschirmabschnitten.
Das heißt, Sie können in der Ausgabe blättern.
Oder eine digitale Transformation könnte man so vormachen, dass Sie
zuerst ein Signal bekommen.
Dieses Signal schicken Sie durch eine Fourier-Transformation, die das
Signal umwandelt in Frequenzen.
Die Frequenzen können Sie manipulieren, zum Beispiel Störfrequenzen
löschen und dann eine inverse Fourier-Transformation durchführen, die
das Original wieder erzeugt, bis auf das, was Sie verändert haben und
haben dann ein geändertes Signal.
Wie gesagt, wenn Sie einen Film im Internet anschauen, dann, ich weiß
nicht durch wie viele Stufen, wo ein Film dann durchwandert, wie es
bei Ihnen ist, sind meistens übertragene Stufen.
Aber auch das ist natürlich ein Fließband.
Manchmal kommt das Fließband ins Stocken.
Also gut geeignet für die Verarbeitung von Datenströmen, zum Beispiel
für Videokodierung und Dekodierung, Videobearbeitung, auch Übersetzer,
Stapelverarbeitung, es haben mehrere Dinge hintereinander zu
bearbeiten.
Für gute Leistung auf Fallrechnung sollte es natürlich so sein, sagen
wir mal, dass hier diese Stufen etwa gleich schnell sind, denn sonst
staut sich an einer an der langsamsten Stufe, stauen sich die Daten
und irgendwann ist auch dieser Puffer erschöpft, voll, dann staut sich
durch diese Stufe zurück, dann staut sich es in dem Puffer und sofort
und schließlich muss irgendwo was stoppen, damit die Stufe 2 fertig
wird und wieder was abnimmt.
Darum sollte man eigentlich hergehen und dafür sorgen, dass die Stufen
etwa gleich schnell sind, wenn sie es nicht sind, dann kann ich Stufen
natürlich auch replizieren, wenn die Stufe 2 zu langsam ist, dann habe
ich halt zwei, drei Instanzen davon, die dann abwechselnd die Daten
bekommen und sie verarbeiten und weiterschicken.
Okay, jetzt für den Rest der Stunde besprechen wir jetzt wieder einen
komplizierten Architekturstil und das ist das Framework oder
Rahmenarchitektur.
Die Rahmenarchitektur ist so, dass sie ein vollständiges Programm
haben, geliefert bekommen, es aber selbst erweitern können, indem sie
bestimmte Schnittstellen und Klassen selbst liefern oder von einem
anderen sich besorgen und eine solche Klasse oder mehrere Klassen
davon gewissermaßen in das Programm einschieben.
Auch das kennen sie schon, wenn sie nämlich wieder in Internetbrowsers
sich denken, da können sie auch bestimmte zusätzliche Erweiterungen in
diesen Browser installieren, wenn er dafür vorgesehen ist.
Zum Beispiel können sie für unterschiedliche Videoformate die
entsprechenden Abspieler installieren oder sie können einen YouTube
-Videoclover installieren, der nicht abspielt, sondern das Video eben
speichert.
Da gibt es also diverse Einschübe und jetzt wollen wir sehen, wie man
das auf die Reihe kriegt, wie man ein Programm schreibt, das mit
Einschüben erweitert werden kann.
Es enthält also eine vollständige Anwendungslogik und damit also ein
komplettes Hauptprogramm.
Von einigen der Klassen in dem Programm können Benutzer oder andere
Entwickler Unterklassen liefern, dabei Methoden überschreiben oder
implementieren.
Und das Rahmenprogramm sieht dann vor, dass diese Einschübe zum
richtigen Zeitpunkt aufgerufen werden.
Das steht ganz im Gegensatz zu der herkömmlichen Architektur, wie sie
es bis jetzt Programme geschrieben haben.
Bis jetzt bekommen sie vollständige Bibliotheken, sagen wir die ganzen
Java -Bibliotheken mit den tausenden von Klassen und Methoden und
schreiben dazu ein neues Anwendungsprogramm, das Hauptprogramm.
Sie schreiben immer main.
Immer haben sie in jeder Abgabe, die sie bis jetzt gemacht haben, kam
main drin vor.
Das mussten sie selbst schreiben.
Das ruft im Wesentlichen irgendwann mal die Bibliotheken auf.
Die Rahmenarchitektur geht andersrum.
Die Rahmenarchitektur hat ein vollständiges Hauptprogramm.
Sie können das Programm starten, ohne dass sie eine einzige Zahl
schreiben, aber sie können Erweiterungen einschieben.
Da gibt es eine lustige Bezeichnung, nämlich das Hollywood-Prinzip.
Sie sind ein aufstrebendes Sternchen, Filmsternchen und gehen zu einem
Hollywood -Producer und sagen ihm, ich wäre also ein sehr guter Satz
für George Clooney oder sowas.
Hier ist meine Karte.
Sagt er, gut, wunderbar, gut, dass ich Sie kenne.
Lassen Sie mir Ihre Karte da.
Don't call us, we will call you.
Okay, wie passt das hier?
Naja, hier ist es so, dass das Hauptprogramm die Aufrufe macht und ich
muss das alles schreiben mit den Aufrufen.
Hier gehe ich nur her und sage, ich stünde zur Verfügung als
Erweiterung und warte auf den Aufruf, dass ich meinen Vertrag kriege
oder einen Aufruf kriege.
Das Hauptbüro besteht bereits und ruft die Erweiterung dieser Benutzer
auf, wenn es will.
Wenn es nicht will, dann will es nicht.
Okay,
wie kriegt man denn das auf die Reihe?
Bis jetzt mussten wir alles benennen, was wir aufrufen.
Das mussten wir kennen.
Wir mussten den Namen der Klasse, der Methode kennen und sie
hinschreiben.
Das können wir jetzt nicht mehr, denn ich weiß ja nicht, wie die
Erweiterung genannt ist.
Könnte einen beliebigen Namen haben.
Ich kann sie so nicht aufrufen.
Wie geht das?
Also nehmen wir an, wir haben eine Rahmenarchitektur, die macht uns
eine Grafik.
Da kann ich grafische Bildchen zeichnen.
Da gibt es Linien und Rechtecke und Ellipsen.
Aber ich darf auch diese davon Unterklassen bilden mit neuen
Zeichenfunktionen.
Wir hatten ja schon gesehen, dass Rechteck und Quadrat Unterklassen
sind unter Umständen.
Nehmen wir an, wir hätten hier mal kein Problem damit.
Wir haben keine sich widersprechenden Funktionalitäten.
Natürlich ist so ein Quadrat ein Rechteck in unserem Fall.
Wir brauchen also Funktionen wie Zeichnen und Löschen, vielleicht noch
ein paar mehr.
Und meine Erweiterungen müssen dann so heißen, müssen dann nur sagen,
ich erweitere Rechteck oder ich erweitere Ellipse oder ich erweitere
Grafik.
Und sonst kann ich den Namen frei wählen.
Aber es muss natürlich diese Methoden müssen zur Verfügung gestellt
werden.
Die muss ich schreiben.
Und wie mache ich jetzt der Rahmenarchitektur bekannt, dass ich eine
Erweiterung habe, die die Ikone heißt.
Das wusste der Programmierer ja nicht.
Der Programmierer der Rahmenarchitektur.
Und das wird jetzt ein bisschen von hinten durch die Brust ins Auge.
Aber ist nicht ganz so schlimm.
Und ich zeige Ihnen das am Beispiel an Eclipse.
Eclipse ist auch so.
Eclipse besteht eigentlich fast nur aus Einschüben.
Und einige davon, glaube ich, haben sie schon eingebaut.
Diese Einschübe werden aus JAR-Dateien gespeichert, also aus Archive
mit einer sogenannten Manifestdatei.
Die Manifestdatei gibt die Bezeichner an, die wir brauchen.
Also, jetzt müssen wir mal schauen, was passiert jetzt.
Das ist jetzt also wirklich Rahmenarchitektur aus Eclipse geholt.
Wenn wir das durchhaben, sind wir fertig für heute.
Da gibt es also einen sogenannten I-Action-Delegate an irgendeiner
Schnittstelle.
Das ist nur eine Schnittstelle, die sagt, ich brauche eine Run-Methode
und eine Selection-Changed-Methode.
Und ich weiß schon, was ich dir als Parameter gebe, aber ich brauche
diese Run-Methoden für eine Erweiterung.
So, jetzt können Sie also hergehen und sagen, ich kann jetzt einen I
-Action -Delegate selbst schreiben als Erweiterung.
Und dann sagen wir mal, die bezeichnen wir Aktion oder meine Aktion.
Also gut, Aktion.
Implementiere Run und Selection-Changed.
Mehr habe ich nicht gemacht.
Jetzt habe ich noch ein zusätzliches Ding.
Ich übersetze das natürlich und brauche eine Manifestdatei.
Diese Manifestdatei wird von dem Archivierer mit erzeugt und es
enthält also so Zeug wie...
Moment, das muss ich schauen.
Das Paket, in dem diese Aktion steht, heißt Erweiterung.
Das sagt es jetzt.
Das sagt es jetzt, die Manifestdatei, unter anderem die Klasse hier,
es gibt es eine neue Klasse, aus dem Paket Erweiterung mit dem Namen
Aktion.
Mit dem wird dem Hauptprogramm hier mitgeteilt, wie dieses Teil heißt.
Noch haben wir die Verbindung nicht und dann kann es natürlich sein,
dass ich für diese Aktion einen Knopf brauche und für diesen Knopf
muss ich noch ein Label angeben und das steht hier.
Ich tue es in diesem Fall.
Ist natürlich auch beliebig.
Das muss also alles auf gesaugt werden.
Den Bezeichner habe ich auch noch, aber den brauche ich jetzt gar
nicht.
So weit, so gut.
Das haben wir jetzt alles geschafft.
Den Aktion-Delegate eine eigene Manifestdatei geliefert, eine
Manifestdatei geholt.
Und jetzt kommt, was muss jetzt noch geschehen?
Naja, das was hier oben steht, ist das jetzt ganz abstrakt gesprochen,
wenn Sie an eine Stelle kommen, wo Sie diese Aktion bräuchten.
Wo Sie diese Aktion bräuchten, ist natürlich blöd, denn noch gibt es
keinen Knopf, wo ich sagen kann, jetzt drücke ich drauf.
Es muss also jetzt, dieses Stück Programm muss jetzt in einem
Menüaufbauprogramm stehen.
Das sagt, jetzt schaue ich mal, was ich noch an zusätzlichen Aktionen
haben könnte.
Dafür erzeuge ich mir Knöpfe und verbinde sie mit der entsprechenden
Funktion, nämlich der Run-Funktion.
Okay, und hier passiert es nämlich, das sagt er jetzt, also hat er
sich diese Manifestdatei durchgelesen in einer Schleife, hat gemerkt,
dass es eine neue Klasse gibt und sagt jetzt, ClassForName und den
Action -Name hat er hier raus abgelesen, nämlich die Erweiterung.
Entschuldigung, Erweiterung.Aktion.
Also liest hier das Ding in eine Zeichenreihe rein, in einen String,
übergibt diesen String, so heißt er, ActionName und was macht jetzt
ClassForName?
ClassForName nimmt diese Zeichenreihe, die er übergeben wurde und
sagt, hola, die Klasse kenne ich noch nicht, schau mal, ob ich sie
laden kann.
Die lade ich mir.
Ach, da gibt es ja diese Klasse aus der Aktionsdatei.
Lädt diese Klasse nach, ist ja schon übersetzt und wenn sie damit
fertig ist, habe ich auch noch einen Aufruf dafür, sagt und macht
davon eine NewInstance, also eine neue Instanz.
Jetzt habe ich auch ein Exemplar davon und merke mir das Exemplar in
der Variable Action.
Und jetzt habe ich diese Klasse und eine Instanz davon und kann jetzt
Run aufrufen und das kommt hier unten, SelectionChanged und ActionRun.
Natürlich muss ich die Parameter versorgen können, das muss jetzt das
Hauptprogramm wissen, wo es die Parameter hernimmt.
SelectionChanged ist, wenn Sie mit der Maus woanders hinfahren und
damit das Ding aufleuchtet, das ist dann SelectionChanged, dass das
dann aktiv wird und die ActionRun führen Sie dann einfach aus, für den
Fall, dass auf den Klopf gedrückt wird.
Ja, so geht das also.
Die Kernfunktion, die wir hier brauchen, ist diese Class.ForName,
diese Funktion oder Methode ForName.
Liest eine Zeichenreihe, lädt die Klasse, die mit diesem Namen
bezeichnet ist und dann haben Sie diese Klasse und für diese Klasse
können Sie eine Instanz erzeugen.
Wunderbar und ich glaube, das war es dann.
Das wird jetzt erklärt.
Also zur Zusammenfassung, wir haben eine Grundversion der Anwendung,
läuft schon, Hauptprogramm ist da, es gibt Erweiterungspunkte, die
Anwendungslogik ist im Rahmenprogramm schon da, aber Speziallogik
können Sie hinzufügen und wir werden dann sehen, um das alles auf die
Reihe zu kriegen, reicht die Class.ForName nicht, sondern wir brauchen
noch mehr Dinge, nämlich Strategie, Fabrikmethode, Abstrakte,
Fabrikschablonenmethode, sind weitere Entwurfsmuster, die werden wir
uns dann im nächsten Abschnitt vornehmen.
Damit sind wir für heute fertig.
Danke, dass Sie so lang da waren.