Das ATOS-Magazin 1/99
ATOS Programmierpraxis
Moderne Zeiten

# Das Objekt und der Objekttyp im Sinne des Programmierers

Nun werden wir uns darauf vorbereiten, die OT/OB-Lib zur Erstellung eigener Speicherobjekttypen zu verwenden. Speicherobjekte waren Objekte, die dazu dienen, bestimmte Information - wie auch immer - zu sichern. Sie ändern ihren äußeren Zustand nicht selbständig, sondern nur auf Befehl.

Der Unterschied, der zwischen Variable und Objekt gemacht wurde, soll noch einmal verdeutlicht werden:

Eine Variable hat jederzeit genau einen konkreten Wert. Unter Umständen kann man diesen Wert beeinflussen. Ein Objekt hingegen hat nach außen hin verschiedene Attribute, die abstrakten Attribute. Hierbei handelt es sich also um verschiedene Werte. Diese Attribute kann man ebenfalls unter Umständen beeinflussen.

Es wurde erwähnt, daß der Variablentyp eine Bezeichnung für den Wertebereich von Variablen ist. Mit dem Begriff `WORD` verbindet man daher eine Stelle, die Werte zwischen -32768 und 32767 annehmen kann. Analog dazu ist der Objekttyp eine Bezeichnung für die Spezifikation des Objektes. Mit dem Begriff `myword` wurden eben beispielsweise Objekte verbunden, wie sie in dem vorangegangen Kapitel beschrieben wurden: `WORD`-Variablen mit Zugriffszähler.

Unter dem Objekttyp "Videokassette" könnte man daher alle Objekte zusammenfassen, die der folgenden Spezifikation genügen:

- hat einen Titel, der gesetzt und ausgelesen werden kann
- hat eine feste Gesamtspielzeit
- hat eine Liste der aufgespielten Filme; es können Filme in die Liste eingetragen werden
  Ein Film habe dabei
  - einen festen Titel, der ausgelesen werden kann
  - eine feste Spielzeit, die ausgelesen werden kann
- die noch freie Spielzeit kann ermittelt werden

Um Objekte diesen Typs im Programm nutzen zu können, muß einmal diese allgemeine Spezifikation umgesetzt werden.

Dazu wird die Implementation dieses Objekttyps in gewisse Teile unterteilt. Zur Beschreibung einer konkreten Implementation eines allgemeinen Speicherobjektes muß Folgendes angegeben werden:

- der Typbezeichner (ein Name)
- die konkreten Attribute (das sind die Speicherobjekte, die innerhalb des Objektes angebracht sind, um die nötigen Werte zu sichern)
  Anm.: Die konkreten Attribute in Speicherobjekten müssen nicht ausschließlich durch Speicherobjekte realisiert sein. Man kann ja zum Beispiel durchaus ein Speicherobjekt konstruieren, das seine Information in Wirklichkeit an einem entfernten Ort ablegt (etwa auf einem anderen Rechner in einem Netzwerk), und dazu innere Komponenten enthält, die selbständig aktiv sind, um die Verbindung zu diesem Ort aufrechtzuerhalten.
- Konstruktor und Destruktor (das sind zwei Unterprogramme, die beschreiben, was beim Anlegen und beim Entfernen eines Objektes diesen Typs zu tun ist; z.B. können hier konkrete Attribute mit Werten vorbelegt werden)
- die abstrakten Attribute (das sind die Zugänge von außen), bestehend aus:
  - Abfragefunktionen, mit denen der äußere Zustand des Objektes abgefragt und nicht beeinflußt werden kann
  - Operationen, mit denen der äußere Zustand des Objektes beeinflußt werden kann
- eventuell lokale Abfragefunktionen und Operationen, die nicht von außen aufgerufen werden können (sie dienen als Unterprogramme für die Realisierung der abstrakten Attribute)

Hierzu kann man in etwa nach dem folgenden Schema vorgehen (zur Verdeutlichung wird das Beispiel in einer Pseudoprogrammiersprache mitvollzogen):

- Man legt den Objekttyp fest, vergibt also einen Namen.

      TYPE videokassette

- Man legt die konkreten Attribute fest. Das sind die "inneren" Speicher eines Objektes diesen Typs, sozusagen die lokalen Variablen. Zu jedem dieser Attribute gibt man den Typ an und wählt einen Attributnamen.

        STRING      titel
        ZAHL        gesamtspielzeit
        LISTE(FILM) filmliste

  Anm.: Der Typ `FILM` müßte noch festgelegt werden, und zwar in genau derselben Weise, wie es gerade mit dem Typ `VIDEOKASSETTE` geschieht.
- Man legt fest, was beim Anlegen und beim Entfernen eines Objektes diesen Typs geschehen soll.

        EXPORT PROCEDURE new(ZAHL gesamtspielzeit)
          ' Gesamtspielzeit einmalig festsetzen
          LET videokassette.gesamtspielzeit=gesamtspielzeit
        RETURN
        EXPORT PROCEDURE free
        RETURN

- Man definiert die Prozeduren und Funktionen, die von außen aufgerufen werden können (die abstrakten Attribute).
  Die Auskunftsfunktionen:

        EXPORT FUNCTION title
          RETURN videokassette.title
        ENDFUNC
        EXPORT FUNCTION film_get(ZAHL filmnummer)
          RETURN videokassette.filmliste.get(filmnummer)
        ENDFUNC
        EXPORT FUNCTION restspielzeit
          RETURN videokassette.gesamtspielzeit - videokassette.bespieltezeit
        ENDFUNC

  Die Operationen:

        EXPORT PROCEDURE title_set(STRING title)
          LET videokassette.title=title
        RETURN
        EXPORT PROCEDURE film_add(FILM new_film)
          @videokassette.filmliste.add(new_film)
        RETURN

- Man definiert die Prozeduren und Funktionen, die nicht von außen aufgerufen werden können. Sie dienen als Unterprogramme für die Prozeduren und Funktionen von oben.

        FUNCTION bespieltezeit
          ZAHL  summe
          ZAHL  filmanzahl
          ZAHL  film
          summe := 0
          filmanzahl := videokassette.filmliste.elementanzahl
          FOR film := 1 TO filmanzahl
            summe := summe + videokassette.film_get(film).spielzeit
          NEXT film
          RETURN summe
        ENDFUNC
      ENDTYPE

So sähe das Ganze dann am Stück aus:

>     TYPE videokassette
>       STRING      titel
>       ZAHL        gesamtspielzeit
>       LISTE(FILM) filmliste
>       EXPORT PROCEDURE new(ZAHL gesamtspielzeit)
>         ' Gesamtspielzeit einmalig festsetzen
>         LET videokassette.gesamtspielzeit=gesamtspielzeit
>       RETURN
>       EXPORT PROCEDURE free
>       RETURN
>       EXPORT FUNCTION title
>         RETURN videokassette.title
>       ENDFUNC
>       EXPORT FUNCTION film_get(ZAHL filmnummer)
>         RETURN videokassette.filmliste.get(filmnummer)
>       ENDFUNC
>       EXPORT FUNCTION restspielzeit
>         RETURN videokassette.gesamtspielzeit - videokassette.bespieltezeit
>       ENDFUNC
>       EXPORT PROCEDURE title_set(STRING title)
>         LET videokassette.title=title
>       RETURN
>       EXPORT PROCEDURE film_add(FILM new_film)
>         @videokassette.filmliste.add(new_film)
>       RETURN
>       FUNCTION bespieltezeit
>         ZAHL  summe
>         ZAHL  filmanzahl
>         ZAHL  film
>         summe := 0
>         filmanzahl := videokassette.filmliste.elementanzahl
>         FOR film := 1 TO filmanzahl
>           summe := summe + videokassette.film_get(film).spielzeit
>         NEXT film
>         RETURN summe
>       ENDFUNC
>     ENDTYPE

Einmal so definiert, können Objekte diesen Typs angelegt und gelöscht werden. Ferner kann man die abstrakten Attribute benutzen. Man arbeitet dann mit den Objekten vom Typ VIDEOKASSETTE ganz analog wie oben mit ZAHL, STRING und FILM. Ein Bsp.:

>     VIDEOKASSETTE kassette_1(240)    ! 240 min
>     VIDEOKASSETTE kassette_2(240)    ! 240 min
>     VIDEOKASSETTE kassette_3(180)    ! 180 min
>     FILM nackte_kanone_1("Die nackte Kanone",112)
>     FILM nackte_kanone_2.5("Die nackte Kanone 2 1/2",129)
>     FILM nackte_kanone_33.3("Die nackte Kanone 33 1/3",104)
>     AUSGABE(AUSGABE.SCREEN) bildschirm
>     '
>     kassette_1.title_set("Nackte Kanone")
>     kassette_1.film_add(nackte_kanone_1)
>     kassette_1.film_add(nackte_kanone_2.5)
>     kassette_1.film_add(nackte_kanone_33.3)
>     '
>     bildschirm.ausgabe(kassette_1.restspielzeit)

Ausblick