ABAP Events: EVENTS, RAISE EVENT, SET HANDLER

Kategorie
ABAP-OO
Veröffentlicht
Autor
Johannes

Eventos en ABAP Object-Oriented permiten comunicacion desacoplada entre objetos. Una clase puede disparar un evento, y otras clases pueden reaccionar a el sin dependencia directa.

Sintaxis

Declaracion de evento

EVENTS <nombre_evento>
[ EXPORTING VALUE(<parametro>) TYPE <tipo> ... ].

Disparar evento

RAISE EVENT <nombre_evento>
[ EXPORTING <parametro> = <valor> ... ].

Definir Handler

METHODS <nombre_handler> FOR EVENT <nombre_evento> OF <clase>
[ IMPORTING <parametro> ... ].

Registrar Handler

SET HANDLER <handler> FOR <objeto>.
SET HANDLER <handler> FOR ALL INSTANCES.

Ejemplos

1. Evento basico

CLASS zcl_button DEFINITION.
PUBLIC SECTION.
" Declaracion de evento
EVENTS clicked.
METHODS press.
ENDCLASS.
CLASS zcl_button IMPLEMENTATION.
METHOD press.
" Disparar el evento
RAISE EVENT clicked.
ENDMETHOD.
ENDCLASS.
" Clase Handler
CLASS zcl_handler DEFINITION.
PUBLIC SECTION.
METHODS on_button_click FOR EVENT clicked OF zcl_button.
ENDCLASS.
CLASS zcl_handler IMPLEMENTATION.
METHOD on_button_click.
WRITE: / 'Boton fue clickeado!'.
ENDMETHOD.
ENDCLASS.
" Uso
DATA: lo_button TYPE REF TO zcl_button,
lo_handler TYPE REF TO zcl_handler.
CREATE OBJECT: lo_button, lo_handler.
" Registrar handler
SET HANDLER lo_handler->on_button_click FOR lo_button.
" Disparar evento
lo_button->press( ). " Salida: "Boton fue clickeado!"

2. Evento con parametros

CLASS zcl_order DEFINITION.
PUBLIC SECTION.
EVENTS order_created
EXPORTING VALUE(ev_order_id) TYPE i
VALUE(ev_customer_id) TYPE string.
METHODS create_order
IMPORTING iv_customer_id TYPE string
RETURNING VALUE(rv_order_id) TYPE i.
PRIVATE SECTION.
DATA: mv_next_id TYPE i VALUE 1000.
ENDCLASS.
CLASS zcl_order IMPLEMENTATION.
METHOD create_order.
" Logica de negocio
mv_next_id = mv_next_id + 1.
rv_order_id = mv_next_id.
" Disparar evento con datos
RAISE EVENT order_created
EXPORTING ev_order_id = rv_order_id
ev_customer_id = iv_customer_id.
ENDMETHOD.
ENDCLASS.
" Handler
CLASS zcl_order_logger DEFINITION.
PUBLIC SECTION.
METHODS on_order_created
FOR EVENT order_created OF zcl_order
IMPORTING ev_order_id ev_customer_id.
ENDCLASS.
CLASS zcl_order_logger IMPLEMENTATION.
METHOD on_order_created.
WRITE: / 'Nuevo pedido:', ev_order_id,
'para cliente:', ev_customer_id.
ENDMETHOD.
ENDCLASS.

3. Multiples Handlers

" Multiples clases pueden reaccionar al mismo evento
CLASS zcl_notification_service DEFINITION.
PUBLIC SECTION.
METHODS on_order_created
FOR EVENT order_created OF zcl_order
IMPORTING ev_order_id ev_customer_id.
ENDCLASS.
CLASS zcl_inventory_service DEFINITION.
PUBLIC SECTION.
METHODS on_order_created
FOR EVENT order_created OF zcl_order
IMPORTING ev_order_id.
ENDCLASS.
" Uso
DATA: lo_order TYPE REF TO zcl_order,
lo_logger TYPE REF TO zcl_order_logger,
lo_notif TYPE REF TO zcl_notification_service,
lo_inventory TYPE REF TO zcl_inventory_service.
CREATE OBJECT: lo_order, lo_logger, lo_notif, lo_inventory.
" Registrar multiples handlers
SET HANDLER lo_logger->on_order_created FOR lo_order.
SET HANDLER lo_notif->on_order_created FOR lo_order.
SET HANDLER lo_inventory->on_order_created FOR lo_order.
" Un evento -> tres handlers ejecutados
lo_order->create_order( 'CUST001' ).

4. Eventos estaticos (CLASS-EVENTS)

CLASS zcl_system_monitor DEFINITION.
PUBLIC SECTION.
" Evento estatico - no necesita instancia
CLASS-EVENTS system_error
EXPORTING VALUE(ev_message) TYPE string.
CLASS-METHODS report_error
IMPORTING iv_message TYPE string.
ENDCLASS.
CLASS zcl_system_monitor IMPLEMENTATION.
METHOD report_error.
RAISE EVENT system_error
EXPORTING ev_message = iv_message.
ENDMETHOD.
ENDCLASS.
" Handler para evento estatico
CLASS zcl_error_logger DEFINITION.
PUBLIC SECTION.
METHODS on_system_error
FOR EVENT system_error OF zcl_system_monitor
IMPORTING ev_message.
ENDCLASS.
" Registro para eventos estaticos
DATA: lo_logger TYPE REF TO zcl_error_logger.
CREATE OBJECT lo_logger.
" Sin FOR <objeto> - porque es estatico
SET HANDLER lo_logger->on_system_error.
" Disparar
zcl_system_monitor=>report_error( 'Error critico!' ).

5. SET HANDLER FOR ALL INSTANCES

" Un handler para TODAS las instancias de una clase
DATA: lo_handler TYPE REF TO zcl_order_logger.
CREATE OBJECT lo_handler.
" Registrar para todas las instancias (existentes y futuras)
SET HANDLER lo_handler->on_order_created FOR ALL INSTANCES.
" Ahora cualquier instancia de zcl_order dispara el handler
DATA: lo_order1 TYPE REF TO zcl_order,
lo_order2 TYPE REF TO zcl_order.
CREATE OBJECT: lo_order1, lo_order2.
lo_order1->create_order( 'CUST001' ). " Handler se ejecuta
lo_order2->create_order( 'CUST002' ). " Handler se ejecuta

6. Desregistrar Handler

" Registrar
SET HANDLER lo_handler->on_order_created FOR lo_order.
" Desregistrar (con ACTIVATION abap_false)
SET HANDLER lo_handler->on_order_created
FOR lo_order
ACTIVATION abap_false.
" Ahora el handler ya no se ejecuta
lo_order->create_order( 'CUST003' ). " Sin reaccion

7. Patron Observer con Eventos

" Sujeto Observable
CLASS zcl_stock DEFINITION.
PUBLIC SECTION.
EVENTS price_changed
EXPORTING VALUE(ev_symbol) TYPE string
VALUE(ev_price) TYPE p.
METHODS set_price
IMPORTING iv_symbol TYPE string
iv_price TYPE p.
ENDCLASS.
CLASS zcl_stock IMPLEMENTATION.
METHOD set_price.
" Actualizar precio y notificar
RAISE EVENT price_changed
EXPORTING ev_symbol = iv_symbol
ev_price = iv_price.
ENDMETHOD.
ENDCLASS.
" Observador 1: Pantalla
CLASS zcl_stock_display DEFINITION.
PUBLIC SECTION.
METHODS on_price_change
FOR EVENT price_changed OF zcl_stock
IMPORTING ev_symbol ev_price.
ENDCLASS.
CLASS zcl_stock_display IMPLEMENTATION.
METHOD on_price_change.
WRITE: / 'Pantalla:', ev_symbol, ev_price.
ENDMETHOD.
ENDCLASS.
" Observador 2: Alerta
CLASS zcl_stock_alert DEFINITION.
PUBLIC SECTION.
METHODS on_price_change
FOR EVENT price_changed OF zcl_stock
IMPORTING ev_symbol ev_price.
PRIVATE SECTION.
DATA: mv_threshold TYPE p VALUE 100.
ENDCLASS.
CLASS zcl_stock_alert IMPLEMENTATION.
METHOD on_price_change.
IF ev_price > mv_threshold.
WRITE: / 'ALERTA:', ev_symbol, 'supera umbral!'.
ENDIF.
ENDMETHOD.
ENDCLASS.

8. Eventos en interfaces

INTERFACE zif_document.
EVENTS document_saved
EXPORTING VALUE(ev_doc_id) TYPE string.
METHODS save.
ENDINTERFACE.
CLASS zcl_invoice DEFINITION.
PUBLIC SECTION.
INTERFACES zif_document.
ALIASES document_saved FOR zif_document~document_saved.
ENDCLASS.
CLASS zcl_invoice IMPLEMENTATION.
METHOD zif_document~save.
" Guardar factura
DATA(lv_doc_id) = 'INV-001'.
" Disparar evento de interfaz
RAISE EVENT document_saved
EXPORTING ev_doc_id = lv_doc_id.
ENDMETHOD.
ENDCLASS.
" Handler para interfaz
CLASS zcl_doc_handler DEFINITION.
PUBLIC SECTION.
METHODS on_doc_saved
FOR EVENT document_saved OF zif_document
IMPORTING ev_doc_id.
ENDCLASS.

9. Eventos con objeto sender

" Parametro SENDER implicito
CLASS zcl_handler DEFINITION.
PUBLIC SECTION.
METHODS on_clicked
FOR EVENT clicked OF zcl_button
IMPORTING sender. " Objeto que disparo el evento
ENDCLASS.
CLASS zcl_handler IMPLEMENTATION.
METHOD on_clicked.
" Acceder al objeto disparador
DATA(lo_button) = sender.
" Llamar metodos del sender si es necesario
" lo_button->get_id( ).
ENDMETHOD.
ENDCLASS.

10. Ejemplo practico: Sistema de pedidos

" Sistema de eventos completo
CLASS zcl_order_system DEFINITION.
PUBLIC SECTION.
EVENTS: order_placed
EXPORTING VALUE(ev_order) TYPE REF TO zcl_order_data,
order_shipped
EXPORTING VALUE(ev_order_id) TYPE string,
order_cancelled
EXPORTING VALUE(ev_order_id) TYPE string
VALUE(ev_reason) TYPE string.
METHODS: place_order
IMPORTING is_data TYPE zst_order_input
RETURNING VALUE(rv_order_id) TYPE string,
ship_order
IMPORTING iv_order_id TYPE string,
cancel_order
IMPORTING iv_order_id TYPE string
iv_reason TYPE string.
ENDCLASS.
" Servicio de Email
CLASS zcl_email_service DEFINITION.
PUBLIC SECTION.
METHODS: constructor,
on_order_placed FOR EVENT order_placed OF zcl_order_system
IMPORTING ev_order,
on_order_shipped FOR EVENT order_shipped OF zcl_order_system
IMPORTING ev_order_id,
on_order_cancelled FOR EVENT order_cancelled OF zcl_order_system
IMPORTING ev_order_id ev_reason.
ENDCLASS.
CLASS zcl_email_service IMPLEMENTATION.
METHOD constructor.
" Auto-registro en sistema de ordenes
DATA(lo_order_system) = zcl_order_system=>get_instance( ).
SET HANDLER: on_order_placed FOR lo_order_system,
on_order_shipped FOR lo_order_system,
on_order_cancelled FOR lo_order_system.
ENDMETHOD.
METHOD on_order_placed.
" Enviar email de confirmacion
WRITE: / 'Email: Pedido confirmado'.
ENDMETHOD.
METHOD on_order_shipped.
" Enviar email de envio
WRITE: / 'Email: Pedido enviado', ev_order_id.
ENDMETHOD.
METHOD on_order_cancelled.
" Enviar email de cancelacion
WRITE: / 'Email: Pedido cancelado', ev_order_id, ev_reason.
ENDMETHOD.
ENDCLASS.

Resumen

AspectoSintaxis
Declarar eventoEVENTS <nombre> EXPORTING ...
Evento estaticoCLASS-EVENTS <nombre> ...
DispararRAISE EVENT <nombre>
Definir handlerMETHODS ... FOR EVENT ... OF ...
RegistrarSET HANDLER <handler> FOR <objeto>
Todas instanciasSET HANDLER ... FOR ALL INSTANCES
DesregistrarSET HANDLER ... ACTIVATION abap_false

Notas importantes / Mejores practicas

  • Los eventos permiten desacoplamiento entre clases.
  • Usar CLASS-EVENTS para eventos que no necesitan instancia.
  • FOR ALL INSTANCES registra para todas las instancias (existentes y futuras).
  • El parametro sender da acceso al objeto disparador.
  • Los handlers se ejecutan sincronicamente en el mismo hilo.
  • Desregistrar handlers cuando el objeto ya no se necesita (evitar memory leaks).
  • Los eventos son ideales para el Patron Observer.
  • En ABAP Cloud/RAP: usar RAP Business Events en lugar de eventos de clase.