Der Model Binder

Klassen mit Anwendungslogik einbinden

Wenn Sie beliebige applikatorische Klassen als Model in eine Webanwendung einbinden wollen, müssen Sie in diesen das Interface zif_model implementieren, das im Kapitel 7 des BSP-Praxisbuchs ausführlich beschrieben ist. Der Vererbungsbaum der einzubindenden Klassen bleibt dabei frei für die Applikation, der die Klasse entstammt.

Wenn die Klassen nicht um das Interface zif_model erweiterbar sind, z.B. weil sie aus einem anderen System kommen und Sie auf das Original keinen Einfluss haben, schreiben Sie eine Adapterklasse, die als Model fungiert und die gewünschten Methodenaufrufe delegiert. Der Adapter trifft zugleich eine Auswahl derjenigen Methoden und Attribute, die für die Webanwendung vorgesehen sind. Auch können die Methodenschnittstellen (weil es ein Adapter ist und kein Proxy) so gestaltet werden, wie es für die Webanwendung optimal ist - intern auf die Originalschnittstellen der Anwendungsklasse abgebildet werden.

Controller-Events

Wie auch immer Sie die Models bilden: Es bleibt Ihnen nicht erspart, die Modelmethoden vom Controller aus aufzurufen. Der Controller ist für die Behandlung von Benutzerereignissen zuständig. Er wertet den fcode aus, der ihn über die auszuführende Operation informiert, und ruft die gewünschten Methoden des jeweils zuständigen Models auf. Die Interpretation des fcode ist eine reine Controllerangelegenheit. Ein Model sollte so etwas wie einen fcode niemals kennen - wenn doch, liegt vermutlich ein Designfehler vor.

Häufig erschöpft sich der für eine Applikation spezifische Controllercode darin, solche fcode-Behandler zu implementieren. Vor allem, wenn Sie das im Buch vorgestellte MVC-Framework verwenden. Denn dann nimmt Ihnen die Klasse zcl_controller bereits die Ansteuerung der richtigen Bilder sowie die Feldauswahl ab. Nur die Benutzerkommandos können natürlich nicht allgemein vorgesehen werden. Oder etwa doch?

Der Model Binder

So wie der immer gleiche Code zum Erzeugen und Ausgaben von Views sich mit Hilfe der Flow Logic-Datei config.xml abstrahieren liess, so gibt es auch einen gewissen typischen Code in fcode-Behandlern. Häufig sehen die Behandler so wie der folgende aus:
method fcode_save.
  data: lo_order type ref to zcl_order.
  lo_order = get_model('order').
  lo_order->save( ).
endmethod.
Für eine kleinere Anwendung haben wir oft eine Handvoll Funktionscode-Behandler dieser Art in einer Klasse, die ansonsten vollständig von der Oberklasse zcl_controller erbt. Es sollte nicht nötig sein, für eine so simple Logik immer wieder neue Controllerklassen einführen zu müssen.

Wenn weiter keine Funktionen benötigt werden und die Feldauswahl mittels zif_model_check vollständig in der Modelklasse abgehandelt werden kann, empfiehlt sich der Einsatz der allgemeinen Klasse zcl_co_model_binder. Hier ist der Code von obigem Typ ein für alle Mal abgebildet.

Mit dem Model Binder als Controller ist es ohne eigenen Controllercode möglich, die Ausführung von Methoden direkt auf Funktionscodes zu legen. Wenn Sie beispielsweise einen Button im View wie folgt definieren,

<z:button fcode="M__order_save" text="<%=otr(z_my_package/save)%>">,
so ruft der Model Binder die Methode save( ) des Models order auf. Wenn im Model eine Feldauswahlregel hinterlegt ist, wird die Methode nur aufgerufen, wenn die Feldauswahl sie als ausführbar bestimmt.

Der Model Binder stellt einen Baustein dar, eine standardisierte Lösung, die hilft, vielen immer gleichen, individuellen Code zu vermeiden. Man kann aber nicht alle Probleme damit lösen. Wenn die Anwendungen etwas komplexer werden, geht es nicht mehr mit dem Model Binder. Beispielsweise ist ein Bild X denkbar, von dem nur auf das Folgebild Y gewechselt werden darf, wenn die Ausführung der Methode keinen Fehler erbrachte. Gab es Fehler, soll man auf Bild X verbleiben.

Indem man wiederkehrende typische Verhaltensmuster dieser Art beobachtet und zusammenfasst, kann man weitere, über den Model Binder hinausgehende Abstraktionsstufen von Controllern entwerfen - Bausteine, die sich in eine künftige Version des Frameworks aufnehmen liessen.

Der Code

Wen es interessiert - hier folgt der relevante Code für die Ereignisbehandlung in zcl_co_model_binder, in der Redefinition der Methode handle_fcode:

* Beginnt Funktionscode mit M__ ?
  if lv_fcode cs zmvc_m_prefix and sy-fdpos eq 0.
    lv_length = strlen( zmvc_m_prefix ).
    split lv_fcode+lv_length at zmvc_comp_sep into lv_model_id lv_method.
    translate lv_method to upper case.
    try.
* Model zur ID heranziehen
        lo_model ?= get_model( lv_model_id ).
        try.
* Wenn das Feldauswahl-Interface implementiert ist: Aufrufen
            lo_model_check ?= lo_model.
            lv_executable = lo_model_check->is_executable( lv_method ).
          catch cx_sy_move_cast_error.
            lv_executable = 'X'.
        endtry.
        if lv_executable = 'X'.
* Methode ausführen
          call method lo_model->(lv_method).
        endif.
      catch cx_sy_dyn_call_error.
      catch zcx_not_found.
    endtry.
  else.
    super->handle_fcode( ).
  endif.

Zurück