Das ATOS-Magazin 3/99
ATOS Programmierpraxis
Moderne Zeiten
Ausfüllen der Prozeduren mit Leben

# Der Fußballspieler

Konstruktor und Destruktor sind, wie oben schon auffiel, zweigeteilt. Der eine Teil (die Funktion `@fussballspieler` beim Konstruktor bzw. analog dazu die Prozedur `@fussballspieler_free` beim Destruktor) dient lediglich dem Anfordern und Freigeben des Objektspeichers. Dies wird dort mittels Aufruf der Bibliotheksfunktionen `@ob_create` bzw. `@ob_free` erledigt. Nach dem Anlegen und vor dem Freigeben von Objektspeichern müssen aber meist Initialisierungs- oder Aufräumaufgaben erledigt werden. Dies geschieht dann in den Prozeduren `@fussballspieler_init` bzw. `@fussballspieler_exit`, welche aus den beiden anderen Routinen heraus aufgerufen werden:

    FUNCTION fussballspieler(name$,position&,staerke&)              !call
      '
      ' Diese Funktion legt ein Objekt des Typs fussballspieler an
      ' und gibt die Objektkennung zurück.
      '
      ' name$       => Name des Fußballspielers (bspw. "Lothar Matthäus")
      ' position&   => Position, auf der der Spieler besonders stark ist.
      '                     fussballspieler_position_tor_&
      '                     fussballspieler_position_abwehr_&
      '                     fussballspieler_position_mitte_&
      '                     fussballspieler_position_sturm_&
      ' staerke&    => Staerke des Spielers im Mittel.
      '                     (0 = sehr schlecht, 100 = sehr gut)
      '
      LOCAL ob#
      '
      ' *** Objektspeicher anfordern ***
      '
      LET ob#=@ob_create(fussballspieler_%)
      '
      ' *** Objektspeicher initialisieren ***
      '
      @fussballspieler_init(ob#,name$,position&,staerke&)
      '
      RETURN ob#
    ENDFUNC
    PROCEDURE fussballspieler_free(ob#)                             !call
      '
      ' Diese Prozedur entfernt ein Objekt des Typs fussballspieler aus
      ' dem Speicher.
      '
      '
      ' *** Objektintern "aufräumen" ***
      '
      @fussballspieler_exit(ob#)
      '
      ' *** Objektspeicher freigeben ***
      '
      @ob_free(ob#,fussballspieler_%)
      '
    RETURN

Die beiden eben aufgeführten Routinen sehen bei allen Objekttypen gleich aus. Man muß lediglich stets die Typnamen und ggf. die Parameter anpassen.

Beim Initialisieren der Objektspeicher müssen zunächst alle konkreten Attributspeicher ihrerseits korrekt initialisiert werden. Dies geschieht durch Aufruf der zum jeweiligen Typ passenden `init`-Prozedur. An diese `init`-Prozedur muß nun dementsprechend auch die Objektkennung des konkreten Attributes übergeben werden. Diese Kennung wird über eine Bibliotheksfunktion, nämlich die Funktion `@ob_attrib`, unter Angabe der Typ- und der Attributkennung, ermittelt:

    PROCEDURE fussballspieler_init(ob#,name$,position&,staerke&)    !call
      '
      ' *** konkrete Attribute initialisieren ***
      '
      @string_init(@ob_attrib(ob#,fussballspieler_%,
                                            fussballspieler_name_%))
      @word_init(@ob_attrib(ob#,fussballspieler_%,
                                            fussballspieler_tor_%))
      @word_init(@ob_attrib(ob#,fussballspieler_%,
                                            fussballspieler_abwehr_%))
      @word_init(@ob_attrib(ob#,fussballspieler_%,
                                            fussballspieler_mitte_%))
      @word_init(@ob_attrib(ob#,fussballspieler_%,
                                            fussballspieler_sturm_%))

Jetzt können die Attributspeicher benutzt und insbesondere mit vernünftigen Werten vorbelegt werden. Im vorliegenden Fall wird der Name des Fußballspielers gesetzt, und es werden die Spielerstärken je nach übergebener Position und Durchschnittsstärke unter Einfluß von etwas Zufall voreingestellt:

      '
      ' *** Spieler einrichten ***
      '
      ' +++ Name setzen +++
      '
      @fussballspieler_name_set(ob#,name$)
      '
      ' +++ Stärke in Tor, Abwehr, Mitte und Sturm festlegen +++
      '     (der Zufall spielt mit)
      '
      SELECT position&
      CASE fussballspieler_position_tor_&      ! Torwart => im Tor gut
        @fussballspieler_tor_set(ob#,RANDOM(20)+staerke&-10)
        @fussballspieler_abwehr_set(ob#,RANDOM(10))
        @fussballspieler_mitte_set(ob#,RANDOM(10))
        @fussballspieler_sturm_set(ob#,RANDOM(10))
      CASE fussballspieler_position_abwehr_&   ! Abwehr => hinten gut
        @fussballspieler_tor_set(ob#,RANDOM(10))
        @fussballspieler_abwehr_set(ob#,RANDOM(20)+staerke&-10)
        @fussballspieler_mitte_set(ob#,RANDOM(staerke& DIV 3))
        @fussballspieler_sturm_set(ob#,RANDOM(staerke& DIV 3))
      CASE fussballspieler_position_mitte_&    ! Mitte => mitte gut
        @fussballspieler_tor_set(ob#,RANDOM(10))
        @fussballspieler_abwehr_set(ob#,RANDOM(staerke& DIV 3))
        @fussballspieler_mitte_set(ob#,RANDOM(20)+staerke&-10)
        @fussballspieler_sturm_set(ob#,RANDOM(staerke& DIV 3))
      CASE fussballspieler_position_sturm_&    ! Stürmer => vorne gut
        @fussballspieler_tor_set(ob#,RANDOM(10))
        @fussballspieler_abwehr_set(ob#,RANDOM(staerke& DIV 3))
        @fussballspieler_mitte_set(ob#,RANDOM(staerke& DIV 3))
        @fussballspieler_sturm_set(ob#,RANDOM(20)+staerke&-10)
      ENDSELECT
      '
    RETURN

In der `init`-Prozedur können auch -- wie oben erwähnt -- Dateien geöffnet werden oder Internetverbindungen aufgebaut werden, falls sich die tatsächlichen Informationspeicher (oder Teile davon) an entfernten Orten befinden. Diese Dateien und Verbindungen kann man in der `exit`-Prozedur wieder schließen bzw. abbauen.

Anschließend muß man (umgekehrt wie beim Initvorgang) jeden einzelnen konkreten Attributspeicher ebenfalls sauber "herunterfahren", denn es könnte ja sein, daß ein solcher noch Resourcen belegt und diese seinerseits erst freigeben muß.

    PROCEDURE fussballspieler_exit(ob#)                             !call
      '
      ' *** konkrete Attribute freigeben ***
      '
      @string_exit(@ob_attrib(ob#,fussballspieler_%,
                                            fussballspieler_name_%))
      @word_exit(@ob_attrib(ob#,fussballspieler_%,
                                            fussballspieler_tor_%))
      @word_exit(@ob_attrib(ob#,fussballspieler_%,
                                            fussballspieler_abwehr_%))
      @word_exit(@ob_attrib(ob#,fussballspieler_%,
                                            fussballspieler_mitte_%))
      @word_exit(@ob_attrib(ob#,fussballspieler_%,
                                            fussballspieler_sturm_%))
      '
    RETURN

Das Ausfüllen der Abfragefunktionen und der Operationen gestaltet sich recht monoton. Zu jedem Objekttyp stehen üblicherweise eine `xxx_set`-Prozedur sowie eine `xxx_get`-Funktion zur Verfügung, über die die Werte in die Objektspeicher eingeschrieben bzw. von dort wieder herausgelesen werden können:

    FUNCTION fussballspieler_name$(ob#)                             !call
      '
      ' Ermittelt den Spielernamen.
      '
      RETURN @string_get$(@ob_attrib(ob#,fussballspieler_%,
                                            fussballspieler_name_%))
    ENDFUNC
    FUNCTION fussballspieler_tor(ob#)                               !call
      $F%
      '
      ' Ermittelt die Tor-Stärke des Spielers.
      '
      RETURN @word_get(@ob_attrib(ob#,fussballspieler_%,
                                            fussballspieler_tor_%))
    ENDFUNC
    FUNCTION fussballspieler_abwehr(ob#)                            !call
      $F%
      '
      ' Ermittelt die Abwehr-Stärke des Spielers.
      '
      RETURN @word_get(@ob_attrib(ob#,fussballspieler_%,
                                            fussballspieler_abwehr_%))
    ENDFUNC
    FUNCTION fussballspieler_mitte(ob#)                             !call
      $F%
      '
      ' Ermittelt die Stärke im Mittelfeld des Spielers.
      '
      RETURN @word_get(@ob_attrib(ob#,fussballspieler_%,
                                            fussballspieler_mitte_%))
    ENDFUNC
    FUNCTION fussballspieler_sturm(ob#)                             !call
      $F%
      '
      ' Ermittelt die Sturm-Stärke des Spielers.
      '
      RETURN @word_get(@ob_attrib(ob#,fussballspieler_%,
                                            fussballspieler_sturm_%))
    ENDFUNC
    PROCEDURE fussballspieler_name_set(ob#,name$)
      @string_set(@ob_attrib(ob#,fussballspieler_%,
                                       fussballspieler_name_%),name$)
    RETURN
    PROCEDURE fussballspieler_tor_set(ob#,staerke&)                 !call
      '
      ' Setzt die Tor-Stärke des Spielers. Die Werte werden auf den
      ' Breich 0..100 gestutzt.
      '
      LET staerke&=MAX(0,MIN(100,staerke&))
      @word_set(@ob_attrib(ob#,fussballspieler_%,
                                      fussballspieler_tor_%),staerke&)
    RETURN
    PROCEDURE fussballspieler_abwehr_set(ob#,staerke&)              !call
      '
      ' Setzt die Abwehr-Stärke des Spielers. Die Werte werden auf den
      ' Breich 0..100 gestutzt.
      '
      LET staerke&=MAX(0,MIN(100,staerke&))
      @word_set(@ob_attrib(ob#,fussballspieler_%,
                                     fussballspieler_abwehr_%),staerke&)
    RETURN
    PROCEDURE fussballspieler_mitte_set(ob#,staerke&)               !call
      '
      ' Setzt die Stärke im Mittelfeld des Spielers. Die Werte werden
      ' auf den Breich 0..100 gestutzt.
      '
      LET staerke&=MAX(0,MIN(100,staerke&))
      @word_set(@ob_attrib(ob#,fussballspieler_%,
                                     fussballspieler_mitte_%),staerke&)
    RETURN
    PROCEDURE fussballspieler_sturm_set(ob#,staerke&)               !call
      '
      ' Setzt die Sturm-Stärke des Spielers. Die Werte werden auf den
      ' Breich 0..100 gestutzt.
      '
      LET staerke&=MAX(0,MIN(100,staerke&))
      @word_set(@ob_attrib(ob#,fussballspieler_%,
                                     fussballspieler_sturm_%),staerke&)
    RETURN

Daß dies hier so monoton aussieht, ist eine Folge der oben gemachten 1:1-Kodierung. Bei Optimierungen oder bei der Verwendung externer Speicher gestaltet sich die Ermittlung und das Ändern der abstrakten Attribute dann entsprechend der gewählten Kodierung aufwendiger.

Der Verein