Events ermöglichen die lose Kopplung zwischen Objekten in ABAP. Ein Objekt (Publisher) kann Ereignisse auslösen, ohne zu wissen, wer darauf reagiert. Andere Objekte (Subscriber) registrieren sich als Handler und werden bei Ereignissen benachrichtigt.
Grundkonzept
- EVENTS: Deklariert ein Ereignis in einer Klasse
- RAISE EVENT: Löst das Ereignis aus (Publisher)
- SET HANDLER: Registriert eine Methode als Event-Handler (Subscriber)
- FOR: Gibt an, für welches Objekt der Handler gilt
Syntax
Event deklarieren
CLASS <klassenname> DEFINITION. EVENTS: <eventname> [ EXPORTING VALUE(<parameter>) TYPE <typ> ].ENDCLASS.Event auslösen
RAISE EVENT <eventname> [ EXPORTING <parameter> = <wert> ].Handler registrieren
SET HANDLER <handler_objekt>-><methodenname> FOR <sender_objekt>.
" Für alle InstanzenSET HANDLER <handler_objekt>-><methodenname> FOR ALL INSTANCES.Beispiele
1. Einfaches Event
" Publisher-Klasse: Löst Events ausCLASS lcl_button DEFINITION. PUBLIC SECTION. EVENTS: clicked.
METHODS: click.ENDCLASS.
CLASS lcl_button IMPLEMENTATION. METHOD click. WRITE: / 'Button wurde geklickt'. RAISE EVENT clicked. ENDMETHOD.ENDCLASS.
" Subscriber-Klasse: Reagiert auf EventsCLASS lcl_form DEFINITION. PUBLIC SECTION. METHODS: on_button_clicked FOR EVENT clicked OF lcl_button.ENDCLASS.
CLASS lcl_form IMPLEMENTATION. METHOD on_button_clicked. WRITE: / 'Form: Button-Klick verarbeitet!'. ENDMETHOD.ENDCLASS.
" VerwendungDATA: lo_button TYPE REF TO lcl_button, lo_form TYPE REF TO lcl_form.
lo_button = NEW #( ).lo_form = NEW #( ).
" Handler registrierenSET HANDLER lo_form->on_button_clicked FOR lo_button.
" Event auslösenlo_button->click( ).
" Ausgabe:" Button wurde geklickt" Form: Button-Klick verarbeitet!2. Event mit Parametern
CLASS lcl_order_processor DEFINITION. PUBLIC SECTION. " Event mit Exportparametern EVENTS: order_completed EXPORTING VALUE(ev_order_id) TYPE i VALUE(ev_amount) TYPE p DECIMALS 2.
METHODS: process_order IMPORTING iv_order_id TYPE i iv_amount TYPE p.ENDCLASS.
CLASS lcl_order_processor IMPLEMENTATION. METHOD process_order. WRITE: / |Bestellung { iv_order_id } verarbeitet.|.
" Event mit Daten auslösen RAISE EVENT order_completed EXPORTING ev_order_id = iv_order_id ev_amount = iv_amount. ENDMETHOD.ENDCLASS.
CLASS lcl_notification_service DEFINITION. PUBLIC SECTION. " Handler-Methode mit SENDER METHODS: on_order_completed FOR EVENT order_completed OF lcl_order_processor IMPORTING ev_order_id ev_amount sender.ENDCLASS.
CLASS lcl_notification_service IMPLEMENTATION. METHOD on_order_completed. WRITE: / |Benachrichtigung: Bestellung { ev_order_id }|. WRITE: / |Betrag: { ev_amount } EUR|. " sender enthält Referenz auf das auslösende Objekt ENDMETHOD.ENDCLASS.
" VerwendungDATA: lo_processor TYPE REF TO lcl_order_processor, lo_notification TYPE REF TO lcl_notification_service.
lo_processor = NEW #( ).lo_notification = NEW #( ).
SET HANDLER lo_notification->on_order_completed FOR lo_processor.
lo_processor->process_order( iv_order_id = 1001 iv_amount = '250.00' ).
" Ausgabe:" Bestellung 1001 verarbeitet." Benachrichtigung: Bestellung 1001" Betrag: 250.00 EUR3. Mehrere Handler für ein Event
CLASS lcl_logger DEFINITION. PUBLIC SECTION. METHODS: on_order_completed FOR EVENT order_completed OF lcl_order_processor IMPORTING ev_order_id ev_amount.ENDCLASS.
CLASS lcl_logger IMPLEMENTATION. METHOD on_order_completed. WRITE: / |LOG: Order { ev_order_id } - { ev_amount } EUR|. ENDMETHOD.ENDCLASS.
CLASS lcl_statistics DEFINITION. PUBLIC SECTION. DATA: mv_total_orders TYPE i, mv_total_amount TYPE p DECIMALS 2.
METHODS: on_order_completed FOR EVENT order_completed OF lcl_order_processor IMPORTING ev_order_id ev_amount.ENDCLASS.
CLASS lcl_statistics IMPLEMENTATION. METHOD on_order_completed. mv_total_orders = mv_total_orders + 1. mv_total_amount = mv_total_amount + ev_amount. WRITE: / |STATS: { mv_total_orders } Bestellungen, Gesamt: { mv_total_amount }|. ENDMETHOD.ENDCLASS.
" Verwendung - Mehrere Handler registrierenDATA: lo_processor TYPE REF TO lcl_order_processor, lo_notify TYPE REF TO lcl_notification_service, lo_logger TYPE REF TO lcl_logger, lo_statistics TYPE REF TO lcl_statistics.
lo_processor = NEW #( ).lo_notify = NEW #( ).lo_logger = NEW #( ).lo_statistics = NEW #( ).
" Alle Handler registrierenSET HANDLER: lo_notify->on_order_completed FOR lo_processor, lo_logger->on_order_completed FOR lo_processor, lo_statistics->on_order_completed FOR lo_processor.
lo_processor->process_order( iv_order_id = 1001 iv_amount = '100.00' ).lo_processor->process_order( iv_order_id = 1002 iv_amount = '200.00' ).
" Alle Handler werden aufgerufen!4. FOR ALL INSTANCES
CLASS lcl_global_logger DEFINITION. PUBLIC SECTION. METHODS: on_any_order_completed FOR EVENT order_completed OF lcl_order_processor IMPORTING ev_order_id sender.ENDCLASS.
CLASS lcl_global_logger IMPLEMENTATION. METHOD on_any_order_completed. WRITE: / |Global Log: Order { ev_order_id } von Processor verarbeitet|. ENDMETHOD.ENDCLASS.
" VerwendungDATA: lo_processor1 TYPE REF TO lcl_order_processor, lo_processor2 TYPE REF TO lcl_order_processor, lo_global_log TYPE REF TO lcl_global_logger.
lo_processor1 = NEW #( ).lo_processor2 = NEW #( ).lo_global_log = NEW #( ).
" Handler für ALLE Instanzen der KlasseSET HANDLER lo_global_log->on_any_order_completed FOR ALL INSTANCES.
lo_processor1->process_order( iv_order_id = 1 iv_amount = 50 ).lo_processor2->process_order( iv_order_id = 2 iv_amount = 75 ).
" Beide werden geloggt!5. Handler deaktivieren
" Handler entfernenSET HANDLER lo_notify->on_order_completed FOR lo_processor ACTIVATION space.
" Oder explizit mit abap_falseSET HANDLER lo_logger->on_order_completed FOR lo_processor ACTIVATION abap_false.
" Handler wieder aktivierenSET HANDLER lo_logger->on_order_completed FOR lo_processor ACTIVATION abap_true.6. Statische Events (CLASS-EVENTS)
CLASS lcl_application DEFINITION. PUBLIC SECTION. " Statisches Event - gehört zur Klasse, nicht zur Instanz CLASS-EVENTS: application_started.
CLASS-METHODS: start.ENDCLASS.
CLASS lcl_application IMPLEMENTATION. METHOD start. WRITE: / 'Anwendung startet...'. RAISE EVENT application_started. ENDMETHOD.ENDCLASS.
CLASS lcl_startup_handler DEFINITION. PUBLIC SECTION. " Handler für Klassen-Event METHODS: on_app_started FOR EVENT application_started OF lcl_application.ENDCLASS.
CLASS lcl_startup_handler IMPLEMENTATION. METHOD on_app_started. WRITE: / 'Startup-Handler: Initialisierung läuft...'. ENDMETHOD.ENDCLASS.
" VerwendungDATA: lo_handler TYPE REF TO lcl_startup_handler.
lo_handler = NEW #( ).
" Bei Klassen-Events: FOR lcl_application (nicht FOR Instanz)SET HANDLER lo_handler->on_app_started FOR lcl_application.
lcl_application=>start( ).7. Events in Interfaces
INTERFACE lif_observable. EVENTS: data_changed EXPORTING VALUE(ev_new_value) TYPE string.ENDINTERFACE.
CLASS lcl_model DEFINITION. PUBLIC SECTION. INTERFACES: lif_observable.
METHODS: set_value IMPORTING iv_value TYPE string.
PRIVATE SECTION. DATA: mv_value TYPE string.ENDCLASS.
CLASS lcl_model IMPLEMENTATION. METHOD set_value. mv_value = iv_value. " Event aus Interface auslösen RAISE EVENT lif_observable~data_changed EXPORTING ev_new_value = mv_value. ENDMETHOD.ENDCLASS.
CLASS lcl_view DEFINITION. PUBLIC SECTION. " Handler für Interface-Event METHODS: on_data_changed FOR EVENT data_changed OF lif_observable IMPORTING ev_new_value.ENDCLASS.
CLASS lcl_view IMPLEMENTATION. METHOD on_data_changed. WRITE: / |View aktualisiert: { ev_new_value }|. ENDMETHOD.ENDCLASS.
" VerwendungDATA: lo_model TYPE REF TO lcl_model, lo_view TYPE REF TO lcl_view.
lo_model = NEW #( ).lo_view = NEW #( ).
SET HANDLER lo_view->on_data_changed FOR lo_model.
lo_model->set_value( 'Neuer Wert' )." Ausgabe: View aktualisiert: Neuer Wert8. Observer Pattern komplett
" Subject InterfaceINTERFACE lif_subject. METHODS: attach IMPORTING io_observer TYPE REF TO lif_observer, detach IMPORTING io_observer TYPE REF TO lif_observer, notify.ENDINTERFACE.
" Observer InterfaceINTERFACE lif_observer. METHODS: update IMPORTING iv_state TYPE string.ENDINTERFACE.
" Konkretes SubjectCLASS lcl_weather_station DEFINITION. PUBLIC SECTION. INTERFACES: lif_subject.
EVENTS: weather_changed EXPORTING VALUE(ev_weather) TYPE string.
METHODS: set_weather IMPORTING iv_weather TYPE string.
PRIVATE SECTION. DATA: mt_observers TYPE TABLE OF REF TO lif_observer, mv_weather TYPE string.ENDCLASS.
CLASS lcl_weather_station IMPLEMENTATION. METHOD lif_subject~attach. APPEND io_observer TO mt_observers. ENDMETHOD.
METHOD lif_subject~detach. DELETE mt_observers WHERE table_line = io_observer. ENDMETHOD.
METHOD lif_subject~notify. LOOP AT mt_observers INTO DATA(lo_observer). lo_observer->update( mv_weather ). ENDLOOP. ENDMETHOD.
METHOD set_weather. mv_weather = iv_weather. lif_subject~notify( ). RAISE EVENT weather_changed EXPORTING ev_weather = mv_weather. ENDMETHOD.ENDCLASS.
" Konkreter ObserverCLASS lcl_phone_display DEFINITION. PUBLIC SECTION. INTERFACES: lif_observer.
METHODS: on_weather_changed FOR EVENT weather_changed OF lcl_weather_station IMPORTING ev_weather.ENDCLASS.
CLASS lcl_phone_display IMPLEMENTATION. METHOD lif_observer~update. WRITE: / |Phone Display: { iv_state }|. ENDMETHOD.
METHOD on_weather_changed. WRITE: / |Phone Event: { ev_weather }|. ENDMETHOD.ENDCLASS.
" VerwendungDATA: lo_station TYPE REF TO lcl_weather_station, lo_phone TYPE REF TO lcl_phone_display.
lo_station = NEW #( ).lo_phone = NEW #( ).
" Observer Patternlo_station->lif_subject~attach( lo_phone ).
" Oder mit EventsSET HANDLER lo_phone->on_weather_changed FOR lo_station.
lo_station->set_weather( 'Sonnig, 25°C' ).9. SENDER Parameter
CLASS lcl_multi_button_handler DEFINITION. PUBLIC SECTION. METHODS: on_button_clicked FOR EVENT clicked OF lcl_button IMPORTING sender. " Referenz auf auslösendes ObjektENDCLASS.
CLASS lcl_multi_button_handler IMPLEMENTATION. METHOD on_button_clicked. " sender enthält die Referenz auf den geklickten Button DATA(lo_button) = sender. WRITE: / 'Ein Button wurde geklickt'.
" Typprüfung und Cast möglich IF sender IS INSTANCE OF lcl_button. " Zugriff auf Button-spezifische Methoden ENDIF. ENDMETHOD.ENDCLASS.
" VerwendungDATA: lo_btn1 TYPE REF TO lcl_button, lo_btn2 TYPE REF TO lcl_button, lo_handler TYPE REF TO lcl_multi_button_handler.
lo_btn1 = NEW #( ).lo_btn2 = NEW #( ).lo_handler = NEW #( ).
SET HANDLER lo_handler->on_button_clicked FOR ALL INSTANCES.
lo_btn1->click( ). " sender = lo_btn1lo_btn2->click( ). " sender = lo_btn210. Praktisches Beispiel: ALV Event-Handling
CLASS lcl_alv_handler DEFINITION. PUBLIC SECTION. METHODS: on_double_click FOR EVENT double_click OF cl_salv_events_table IMPORTING row column.
METHODS: on_link_click FOR EVENT link_click OF cl_salv_events_table IMPORTING row column.ENDCLASS.
CLASS lcl_alv_handler IMPLEMENTATION. METHOD on_double_click. WRITE: / |Doppelklick auf Zeile { row }, Spalte { column }|. ENDMETHOD.
METHOD on_link_click. WRITE: / |Link geklickt in Zeile { row }, Spalte { column }|. ENDMETHOD.ENDCLASS.
" Verwendung mit SALVDATA: lo_alv TYPE REF TO cl_salv_table, lo_events TYPE REF TO cl_salv_events_table, lo_handler TYPE REF TO lcl_alv_handler.
TRY. cl_salv_table=>factory( IMPORTING r_salv_table = lo_alv CHANGING t_table = lt_data ).
" Events holen lo_events = lo_alv->get_event( ).
" Handler registrieren lo_handler = NEW #( ). SET HANDLER: lo_handler->on_double_click FOR lo_events, lo_handler->on_link_click FOR lo_events.
lo_alv->display( ).
CATCH cx_salv_msg.ENDTRY.Event-Typen
| Typ | Deklaration | SET HANDLER FOR |
|---|---|---|
| Instanz-Event | EVENTS | Spezifische Instanz |
| Klassen-Event | CLASS-EVENTS | Klasse selbst |
| Interface-Event | EVENTS in Interface | Implementierende Klasse |
Wichtige Hinweise / Best Practice
- Events ermöglichen lose Kopplung – Publisher kennt Subscriber nicht.
- SENDER enthält die Referenz auf das auslösende Objekt.
FOR ALL INSTANCESfür globale Handler (Logging, Monitoring).- ACTIVATION space/abap_false zum Deaktivieren von Handlern.
- Events sind synchron – Handler werden sofort ausgeführt.
- CLASS-EVENTS für klassenweite Ereignisse ohne Instanz.
- Nutzen Sie
INTERFACEfür Events bei loser Kopplung. - Observer Pattern ideal für UI-Updates und Benachrichtigungen.
- Handler-Methoden müssen die richtige Signatur haben (
FOR EVENT ... OF). - Vorsicht bei zirkulären Event-Ketten – können Endlosschleifen verursachen.