Design Patterns in ABAP – Observer

SAPObserver design pattern can be easily demonstrated on a chat service where you have a server and several clients (observers). Once a client sends a message, server receives it and RAISES an EVENT (eg NEW_MESSAGE_RECEIVED) which is OBSERVED by all connected clients (observers) and such message is subsequently displayed in message dialog on all clients.

In ABAP world it can be demonstrated eg. on an ALV where a change in it’s cell contents raises an event which is observed and further handled in various observers (eg another ALV which automatically updates its contents).

In our example we will have a server (main process) which will trigger an EVENT each time a message is received.
All registered clients (in our case it will be a Dialog and Printer clients) will handle the event according to their implementations.

Observer Class diagram

Server part

Our server (main process) receives a message from clients via public method PUT_MESSAGE and can raise an event called NEW_MESSAGE.

*** SERVER PART ***
CLASS lcl_server DEFINITION.
  PUBLIC SECTION.
    METHODS:
      put_message IMPORTING i_msg TYPE string.
    EVENTS
      new_message EXPORTING VALUE(msg) TYPE string.
ENDCLASS.

CLASS lcl_server IMPLEMENTATION.
  METHOD put_message.
*** Debug info ***
    WRITE:/ 'Server received new message:'.
    WRITE:/ '  ', i_msg.

    WRITE:/ 'Server raises event NEW_MESSAGE'.
    SKIP 2.
    RAISE EVENT new_message EXPORTING msg = i_msg.
  ENDMETHOD.
ENDCLASS.

Client interface

Because we can have multiple clients handling the data differently, we implemented a common interface that all clients will use, but the behaviour of each client can be different in it’s implementation as I’ll show later with a DIALOG and a PRINTER clients.

*** CLIENT INTERFACE ***
INTERFACE lif_client.
  METHODS:
    send IMPORTING i_msg TYPE string,
    on_new_message FOR EVENT new_message OF lcl_server
      IMPORTING msg.
  DATA:
    mo_server TYPE REF TO lcl_server READ-ONLY.
ENDINTERFACE.

Dialog Client

*** DIALOG CLIENT ***
CLASS lcl_dialog_client DEFINITION.
  PUBLIC SECTION.
    INTERFACES lif_client.
    METHODS:
      constructor
        IMPORTING
          io_server TYPE REF TO lcl_server.
ENDCLASS.

CLASS lcl_dialog_client IMPLEMENTATION.
  METHOD constructor.
    lif_client~mo_server = io_server.
  ENDMETHOD.

  METHOD lif_client~send.
*** Debug info ***
    WRITE: / 'DIALOG is sending new message'.
    lif_client~mo_server->put_message(
      EXPORTING
        i_msg = i_msg
    ).
  ENDMETHOD.

  METHOD lif_client~on_new_message.
*** Debug info ***
    WRITE: / 'DIALOG received new message:'.
    WRITE: / '  ', msg.
  ENDMETHOD.
ENDCLASS.

Printer Client

*** PRINTER CLIENT ***
CLASS lcl_printer_client DEFINITION.
  PUBLIC SECTION.
    INTERFACES lif_client.
    METHODS:
      constructor
        IMPORTING
          io_server TYPE REF TO lcl_server.
ENDCLASS.

CLASS lcl_printer_client IMPLEMENTATION.
  METHOD constructor.
    lif_client~mo_server = io_server.
  ENDMETHOD.

  METHOD lif_client~send.
*** Debug info ***
    WRITE: / 'PRINTER is sending new message'.
    lif_client~mo_server->put_message(
      EXPORTING
        i_msg = i_msg
    ).
  ENDMETHOD.

  METHOD lif_client~on_new_message.
*** Debug info ***
    WRITE: / 'PRINTER received new message:'.
    WRITE: / '  ', msg.
  ENDMETHOD.
ENDCLASS.

Test program

*** TEST PROGRAM ***
START-OF-SELECTION.
  DATA:
    lo_server   TYPE REF TO lcl_server,
    lo_client_1 TYPE REF TO lif_client,
    lo_client_2 TYPE REF TO lif_client.

* Creating server instance
  CREATE OBJECT lo_server.
* Creating dialog client instance
  CREATE OBJECT lo_client_1 TYPE lcl_dialog_client
    EXPORTING
      io_server = lo_server.
* Creating printer client instance
  CREATE OBJECT lo_client_2 TYPE lcl_printer_client
    EXPORTING
      io_server = lo_server.

* Register event handlers
  SET HANDLER lo_client_1->on_new_message FOR lo_server.
  SET HANDLER lo_client_2->on_new_message FOR lo_server.

* Send new message from dialog client to server
  lo_client_1->send( 'Hello world' ).

Output

Observer design pattern - Output

Leave a Reply