oberon index <- ^ -> mail ?
Weiter: Weitere Implementierungen, davor: Konzeption, darüber: Autorisierungsprotokolle.

Realisierung

Persistenz

Eine Frage, die bei der Formulierung einer neuen Abstraktion früh geklärt werden sollte, ist, auf welche andere etwa schon vorhandene Abstraktion sie aufbauen kann. Eine solche übergeordnete Abstraktion gibt es immer, denn laut Konvention bilden ja alle Verbundtypen statisch eine gemeinsame Hierarchie, sind also mindestens Erweiterungen von Objects.Object.

Im Falle der Shards sollen die Objekte allerdings wesentlich speziellerer Natur sein, nämlich uneingeschränkt transportabel. Daher verlangen wir von vornherein Persistenz. Shards.Pot und Shards.Lid müssen also als Erweiterungen von PersistentDisciplines.Object in die Typenhierarchie eingeführt werden, und korrekte Implementierungen benötigen die obligatorischen Methoden (marshalling procedures) für PersistentObjects.

Trivialfälle

Wie bereits angedeutet, werden Autorisierungsentscheidungen als Methoden der Shards.Pot-Objekte ausgeführt. Die denkbar einfachste Möglichkeit für eine solche "Entscheidung" ist die stereotype, vom präsentierten Gegenstück also völlig unabhängige Antwort. Es liegt daher nahe, einen stets ablehnenden und einen stets annehmenden Kontrolleur als triviale Implementierungen in das Basismodul Shards aufzunehmen.

Zu beachten ist, daß es umgekehrt einen Schlüssel, der überall bzw. nirgends paßt, nicht geben kann. Ein beliebiges unbekanntes Shards.Lid-Objekt wird zwar von den meisten Kontrolleuren zurückgewiesen werden, aber es gibt keine prinzipielle Möglichkeit, ein bestimmtes Verhalten zu erzwingen.

Konstruktoren

Jede Implementierung wird Möglichkeiten anbieten, Instanzen ihrer Objekte mit vorgegebenen Eigenschaften zu erzeugen. In vielen einfachen Fällen wird es genügen, lediglich "Töpfe" zur Verfügung zu stellen, die darauf eingerichtet sind, bei Bedarf passende "Deckel" nachzuliefern, wofür die optionale zweite Methode Shards.Supply vorgesehen ist. Diese Vorgehensweise ist aber nicht zwingend, weil sie schon aus konzeptionellen Gründen nicht immer möglich ist (man denke an den Topf, der überhaupt keinen Deckel akzeptiert). Auch ist es denkbar, daß zum Herstellen eines Deckels mehr Information benötigt wird, als der Topf allein enthält, oder daß in sonst einer Weise der Kontext eine Rolle spielt. Daher braucht Supply nicht implementiert zu werden und, falls doch, nicht unbedingt Erfolg zu garantieren.

Kombinationen

Eine Anwendung, die etwas schützen möchte, installiert einen Kontrolleur (Pot) und schaltet vor jeden Zugriff auf das geschützte Gut einen Aufruf der entsprechenden Methode (Fits). Nun erhebt sich die Frage, ob sich die Eigenschaften mehrerer Kontrolleure zu einem komplizierteren Prüfverfahren kombinieren lassen, etwa, um verschiedene Bedingungen alternativ zu akzeptieren (wie bei einer Schließanlage mit Hauptschlüsseln), oder um andererseits zur Erhöhung der Sicherheit mehrere Beschränkungen gleichzeitig einzufordern.

Um das Protokoll nicht zu verletzen, soll auch das zusammengesetzte Verfahren nur einen "Topf" und einen "Deckel" als Bezugspunkte benutzen. Im ersten Fall ist dies sehr leicht möglich. Soll ein Topf mehrere verschiedene Deckel akzeptieren, braucht er nur seinerseits mehrere einfache Töpfe enthalten und deren Kontrollmethoden mit "oder" zu verknüpfen.

Der zweite Fall ist kritischer. Ein "Supertopf", der mehrere Kontrollen mit "und" verknüpft, wird vermutlich jeden gewöhnlichen Deckel zurückweisen. Um so verfahren zu können, bedarf es also auch eines "Superdeckels", der gleichzeitig von verschiedenen Töpfen akzeptiert wird. Ein Deckel hat als an diesem Verfahren nur passiv Beteiligter allerdings nicht die Möglichkeit, zu bestimmen, welche Methode auf ihn anzuwenden ist. Dieses Problem läßt sich auf der Ebene der Abstraktion lösen, wenn sie zusammengesetzte Deckel intern so verwaltet, daß externe Implementierungen davon gar nicht behelligt werden. Eine implementierende Methode wird also, auch wenn ein "Superdeckel" getestet wird, implizit nur mit "Elementardeckeln" konfrontiert, dafür aber unter Umständen mehrmals.

Es bleibt festzuhalten, daß die Möglichkeit, Deckel zu kombinieren (mit Hilfe der Funktion Shards.CombineLids) genügt, um jede Art von "und"- und "oder"-Verknüpfungen sowohl von Töpfen als auch Deckeln innerhalb des einfachen Protokolls zuzulassen.

Programmierung

Dieses Codebeispiel zeigt den gesamten Definitionsteil des Moduls Shards in Oberon. Zuerst werden die beiden Objekttypen Pot und Lid definiert; es folgen die Datentypen der Schnittstelle für Implementierungen (interface). Als Prozeduren treten natürlich die beiden Methoden Fits und Supply auf sowie die Initialisierungsroutine für neue Objekte, Init.

Drei Konstruktoren ebnen den Zugang zu den intern implementierten Objekttypen: CombineLids erzeugt einen "Superdeckel" aus zwei Komponenten -- da diese wiederum zusammengesetzt sein können, lassen sich auch größere Konglomerate bilden --, CreateSimplePot liefert die beiden Sorten trivialer Töpfe und CreateSomeLid einen Deckel "ohne besondere Eigenschaften".

Zu bemerken ist, daß die wahren Typen der so erzeugten Objekte, die ja Erweiterungen der abstrakten Typen sind, gar nicht exportiert werden. Hinter dieser "Geheimniskrämerei" steckt das Bestreben, der Implementierung sogar in der Frage, ob eigene Datentypen verwendet werden, größtmögliche Freiheit zuzugestehen und dadurch Abhängigkeiten zu vermeiden.

Dieses Codefragment zeigt anhand der Methode Shards.Fits, wie eine typische Aufgabenverteilung zwischen einer Methode der Abstraktion und der zugehörigen implementierenden Methode aussehen kann:

Eine externe Implementierung der Methode Fits benötigt noch einen Test, ob ihr Lid-Argument vom richtigen (eigenen) Typ ist, bevor sie dasselbe bearbeitet; im übrigen ist sie nur für die eigentliche Aufgabe, die gewünschte Kontrolle auf ihre Weise durchzuführen, verantwortlich.

Die Kontrolle selbst wird als elementarer Vorgang betrachtet, dessen Ergebnis nüchtern als Funktionsresultat zurückzumelden ist, ohne etwa den Ablehnungsfall mit großem Lärm als Ausnahmesituation zu behandeln.


oberon index <- ^ -> mail ?
Weiter: Weitere Implementierungen, davor: Konzeption, darüber: Autorisierungsprotokolle.
Martin Hasch, Oct 1996