next up previous
Nächste Seite: Zusammenfassung Aufwärts: Objekt-Modelle von Bibliotheken Vorherige Seite: Delegationen und Abhängigkeiten zwischen

Typen oder Markierungen als Objekte

Selbst wenn die Programmiersprache Typentests wie z.B. Oberon zur Verfügung stellt, ist dies noch lange nicht so allgemein wie die Einführung von Typen (oder Klassen) als 1st class objects. So ist es beispielsweise in Oberon nicht möglich herauszufinden, ob der Typ eines Objekts eine Erweiterung des Typs eines anderen Objekts ist. Smalltalk hat zuerst Metaklassen eingeführt und andere Sprachen wie z.B. Self sehen überhaupt keinen Unterschied mehr zwischen Klassen und Objekten.5.6

Wenn die Programmiersprache selbst nicht die notwendige Unterstützung liefert, ist es prinzipiell kein Problem, sie im Rahmen einer Bibliothek nachzuholen, wobei dann allerdings Konventionen entstehen, die konsequent einzuhalten sind, um diese Möglichkeiten umfassend ausnutzen zu können. Um diese Konventionen nicht auf alle zu kreierenden Objekte auszudehnen, werden in der Ulmer Oberon-Bibliothek Typen als 1st class objects nur für Erweiterungen von Services.Object5.7angeboten, das selbst eine Erweiterung von Disciplines.Object ist.

Und so sehen die Konventionen in der Ulmer Oberon-Bibliothek aus:

Wenn all diese Vorbereitung stattgefunden haben, ist es möglich, den Typ eines jeden Objekts zu ermitteln und als Objekt zu behandeln, wenn der Typ des Objekts eines Erweiterung von Services.Object ist. Da Services.Type eine Erweiterung von Disciplines.Object ist, besteht auch insbesondere die Möglichkeit, Disziplinen an Typen anzuheften.

Dieser Mechanismus ist von besonderem Interesse für sekundäre Abstraktionen, die nicht von dem Modul unterstützt werden, das für die Implementierung der primären Abstraktion zuständig ist, und für die andererseits auch keine allgemein gültige Implementierung existiert. Stattdessen wird die Implementierung der sekundären Abstraktion von beliebig vielen hinzukommenden Modulen realisiert, die den entsprechenden Dienst jeweils für bestimmte Typen und deren Ableitungen anbieten. Dies wird von Services direkt unterstützt und daher ergab sich auch der Name dieses Moduls. Ein mögliches Szenario hierfür illustriert die Abbildung 5.5:

SSSs:
Eine sekundäre Abstraktion, deren Implementierung von dem Typ eines Objekts abhängt und daher nicht generell vorgegeben werden kann. Da diese Abstraktion jedoch erst später hinzugekommen ist, können zu ihrer Unterstützung nicht die Implementierungen primärer Abstraktionen aufgebläht werden.
AAAs:
Eine primäre Abstraktion mit den Implementierungen XXXs, YYYs und ZZZs, die lange vor der Entstehung von SSSs eingefroren worden sind.
SSSsForXXXs:
Dieses Modul implementiert die sekundäre Abstraktion SSSs für Objekte vom Typ XXXs.XXX oder einer Erweiterung davon. Analog unterstützt SSSsForYYYs die sekundäre Abstraktion für YYYs.
SSSsForAAAs:
Hier wird die Unterstützung für alle Erweiterungen von AAAs.AAA angeboten, für die es keine spezielle Implementierung gibt. In diesem Szenario betrifft dies ZZZs.

Genauso wie bei primären Abstraktionen bieten sich auch hier Schnittstellen-Records an (siehe §2.7), die von SSSs öffentlich definiert und über eine Support-Operation mit dem jeweiligen Typ verbunden werden. Als Beispiel (Importhierarchie in Abbildung 5.6) sei hier eine Variante von PrintableObjects gegeben, die auf Services basiert:5.8

Abbildung: Importhierarchie zur sekundären Abstraktion PrintableObjects
\begin{figure}\epsfig{file=printable.eps}\end{figure}

DEFINITION PrintableObjects;

   IMPORT Services, Streams;

   (* secondary abstraction for printable objects
      which is usually to be supported by type-dependent modules
   *)

   TYPE
      PrintProc = PROCEDURE (s: Streams.Stream; object: Services.Object);

   PROCEDURE Support(for: Services.Type; print: PrintProc);
      (* supply print method for all instances of `for' and its extensions *)

   PROCEDURE SetDefault(s: Streams.Stream; default: ARRAY OF CHAR);
      (* sets the per-stream default output text for objects
         which do not have an associated print method
      *)

   PROCEDURE Print(s: Streams.Stream; object: Services.Object);
      (* call the print method of `object', or, if not present,
         the per-stream default text, or, if not present, a question mark
      *)

END PrintableObjects.

In Support wird die Schnittstelle dann an den Typ über eine Disziplin geheftet:

PROCEDURE Support(for: Services.Type; print: PrintProc);
   (* supply print method for all instances of `for' and its extensions *)
   VAR
      typeDisc: TypeDiscipline;
BEGIN
   Services.Define(for, service, NIL);
   NEW(typeDisc); typeDisc.id := typeDiscID;
   typeDisc.print := print;
   Disciplines.Add(for, typeDisc);
END Support;

Bei der Anwendung wird dann jeweils nach dem unterstützten Basistyp des übergebenen Objekts gesucht und dort die Schnittstelle der Disziplin wieder entnommen:

PROCEDURE Print(s: Streams.Stream; object: Services.Object);
   (* call the print method of `object', or, if not present,
      the per-stream default text, or, if not present, a question mark
   *)
   VAR
      baseType: Services.Type;
      typeDisc: TypeDiscipline;
      streamDisc: StreamDiscipline;
BEGIN
   Services.GetSupportedBaseType(object, service, baseType);
   IF (baseType # NIL) &
         Disciplines.Seek(baseType, typeDiscID, typeDisc) THEN
      typeDisc.print(s, object);
   ELSIF Disciplines.Seek(s, streamDiscID, streamDisc) THEN
      Write.StringS(s, streamDisc.defaultText);
   ELSE
      Write.StringS(s, defaultText);
   END;
END Print;

Ein Diensteanbieter wie beispielsweise PrintableCollections muß dann nur noch seine Implementierung mittels PrintableObjects.Support registrieren:

MODULE PrintableCollections;

   (* implements PrintableObjects for Collections *)

   IMPORT Collections, Disciplines, PrintableObjects, Services,
      Streams, Write;

   PROCEDURE PrintCollection(s: Streams.Stream; object: Services.Object);
      VAR
         member: Disciplines.Object;
         first: BOOLEAN;
   BEGIN
      WITH object: Collections.Collection DO
         Write.CharS(s, "(");
         Collections.First(object);
         first := TRUE;
         WHILE Collections.Next(object, member) DO
            IF first THEN
               first := FALSE;
            ELSE
               Write.StringS(s, ", ");
            END;
            IF member IS Services.Object THEN
               PrintableObjects.Print(s, member(Services.Object));
            ELSE
               Write.CharS(s, "?");
            END;
         END;
         Write.StringS(s, ")");
      END;
   END PrintCollection;

   PROCEDURE Init;
      VAR type: Services.Type;
   BEGIN
      Services.SeekType("Collections.Collection", type);
      PrintableObjects.Support(type, PrintCollection);
   END Init;

BEGIN
   Init;
END PrintableCollections.


next up previous
Nächste Seite: Zusammenfassung Aufwärts: Objekt-Modelle von Bibliotheken Vorherige Seite: Delegationen und Abhängigkeiten zwischen
Andreas Borchert 2000-12-18