ABAP Objects: Tutorial para el manejo de Eventos (Events)
En este tutorial de ABAP Objects conoceremos qué es un Evento en ABAP Objects, su sintaxis, y mediante un ejemplo sencillo aprenderemos como usarlos. Finalmente probaremos su uso mediante un programa ejemplo en ABAP.
Un Evento es una acción reconocida por un objeto (como hacer un clic del mouse o presionar una tecla), y para el cual se puede escribir código para responder. Los eventos pueden ocurrir como resultado de una acción por parte del usuario o código del programa, pero también pueden ser "disparados" por el sistema. Además, es posible desarrollar eventos propios "customizados" que son "levantados" por sus propios objetos y manejados por otros.
Los eventos son usados por los objetos o las clases para desencadenar métodos en otros objetos o clases.
En ABAP Objects, "disparar" y "controlar-manejar" un evento significa que algunos métodos actúan como disparadores (triggers) de eventos y otros métodos actúan como manejadores, es decir, reaccionan a ellos. Por lo tanto, los métodos manejadores van a ejecutarse cuando el evento sea “levantado” por el método que lo dispara.
Para que un objeto o clase maneje el evento de otro objeto o clase se debe establecer una relación en tiempo de ejecución. Es decir, dinámicamente el método del objeto que va a manejar el evento se va a “suscribir” al objeto que lo va a disparar. Esto es: el método declara que es él quien se va a encargar de manejarlo. Lo mismo puede ocurrir para las clases: un método estático se puede suscribir a otra clase para manejar un evento de clase.
Así, se pueden distinguir dos tipos de eventos: los de instancia y los estáticos.
Los de instancia corresponden a eventos de objetos y los estáticos, a los eventos de clases.
Para disparar un evento, una clase debe realizar dos acciones:
1. Declarar el evento en la parte de la declaración. Para declarar eventos de instancia se utiliza la sentencia EVENTS evt EXPORTING... VALUE(e1 e2 ...) TYPE type [OPTIONAL]. Para declarar eventos estáticos se utiliza la sentencia CLASS-EVENTS evt. Cuando se declara un evento se puede usar el agregado EXPORTING para pasarle un parámetro al método manejador. Este pasaje siempre se hace por valor. Además los eventos de instancia exportan siempre un parámetro de manera implícita llamado SENDER. Dicho parámetro contiene una referencia al objeto que levantó el evento. El parámetro SENDER se usará en el ejemplo que se presentará en breve.
2. Disparar el evento en alguno de sus métodos con la sentencia RAISE EVENT.
Los dos tipos de eventos (de instancia y de clase) se pueden declarar tanto en una interfaz como en una clase. Por lo tanto, profundizando aún más el concepto, se pueden identificar cuatro tipos de eventos:
1) Evento de instancia declarado en una clase.
2) Evento de instancia declarado en una interfaz.
3) Evento estático declarado en una clase.
4) Evento estático declarado en una interfaz.
Es importante conocer de qué tipo de evento se trata porque de eso dependerá la sintaxis y efecto de la sentencia SET HANDLER. Dicha sentencia es la que logra que un método de un objeto o clase (el manejador) se suscriba a otro objeto o clase (el disparador), en tiempo de ejecución.
En el presente tip se detallarán los pasos a seguir para implementar dos clases en ABAP Objects: una que dispara el evento (trigger) y otra clase que lo maneja (handler), para posteriormente en un programa ejemplo verificar su funcionamiento. El ejemplo implementa un evento de instancia declarado en una clase (en la clasificación de arriba corresponde a la opción 1)
Consigna para el desarrollo del ejemplo
Se posee una mascota que tiene un único atributo: la energía (se asume de 1 a 10). Cuando duerme n horas, la energía aumenta en n o hasta el máximo. Cuando juega n horas, disminuye en n. La energía de la mascota no puede disminuir por debajo del mínimo. En tal caso su amo inmediatamente "la manda a dormir" 8 horas .
Implementación de una solución posible:
Pasos a seguir para definir las clases y los métodos asociados
La solución propuesta consiste en definir dos clases: Z_MASCOTA y Z_AMO. Para la clase Z_MASCOTA se van definir los métodos CONSTRUCTOR, JAUGAR, DORMIR, GET_NOMBRE, GET_STRING, y el evento CANSADO. Para la clase _Z_AMO se va a definir el método RECEIVE.
Entonces, cuando un objeto mascota juegue en exceso, levantará mediante la sentencia RAISE EVENT el evento CANSADO en el método jugar. El evento CANSADO será manejado por un método denominado RECEIVE, de un objeto amo, que se encargará de "mandarla a dormir" (ésto se simulará también con otro método (denominado dormir) de la clase mascota).
Pasos para definir la clase Z_MASCOTA e implementar sus métodos
1) En la transacción SE80/SE24 crear la clase Z_MASCOTA. (Si el lector lo desea puede optar por definir las clases localmente en un programa Z.)
2) En la clase Z_MASCOTA definir los atributos y métodos que se ilustran a continuación:
3) En la solapa “Events” definir el evento público de instancia CANSADO:
4) A continuación se van a mostrar los parámetros y las implementaciones de los métodos declarados previamente en la clase Z_MASCOTA.
4.1) Método CONSTRUCTOR:
Parámetros:
Implementación:
METHOD constructor. nombre = i_nombre. energia = 5. ENDMETHOD. |
4.2) Método JUGAR:
Parámetros:
Implementación:
METHOD jugar. DATA energia_nueva TYPE i. energia_nueva = energia - i_horas. IF energia_nueva LT energia_minima. energia = energia_minima. RAISE EVENT cansado. ELSE. energia = energia_nueva. ENDIF. ENDMETHOD.
|
4.3) Método DORMIR:
Parámetros:
Implementación:
METHOD dormir. DATA energia_nueva TYPE i. energia_nueva = energia + i_horas. IF energia_nueva GT energia_maxima. energia = energia_maxima. ELSE. energia = energia_nueva. ENDIF. ENDMETHOD. |
4.4) Método GET_STRING:
Parámetros:
Implementación:
METHOD get_string. DATA energia_string TYPE c LENGTH 2. WRITE energia TO energia_string. CONCATENATE nombre ', energia:' energia_string INTO r_string SEPARATED BY ' '. ENDMETHOD. |
4.5) Método GET_NOMBRE
Parámetros:
Implementación:
METHOD get_nombre. r_nombre = nombre. ENDMETHOD. |
5) Activar la clase Z_MASCOTA
Pasos para definir la clase Z_AMO e implementar su método
1) En la transacción SE80/SE24 crear la clase Z_AMO.
2) En la clase Z_AMO definir el método manejador del evento CANSADO (RECEIVE), luego oprimir el botón “Detail view” especificando la información adecuada y finalmente oprimir “Change”:
3) Método RECEIVE:
Parámetros:
Implementación:
METHOD receive. DATA: msg TYPE string, nombre_mascota TYPE string. sender->dormir( 8 ). nombre_mascota = sender->get_nombre( ). CONCATENATE 'Soy el amo y mande a dormir a' nombre_mascota INTO msg SEPARATED BY ' '. MESSAGE msg TYPE 'I'. ENDMETHOD. |
4) Activar la clase Z_AMO.
Programa Ejemplo para comprobar el funcionamiento de las clases y evento implementado
1) Por último se va a mostrar el código de un programa Z para testear las clases.
Código del ejemplo:
*&---------------------------------------------------------------------* *& Report Z_PRUEBA_MASCOTA *& *&---------------------------------------------------------------------* *& *& *&---------------------------------------------------------------------*
REPORT Z_PRUEBA_MASCOTA. DATA: mascota1 type REF TO z_mascota, mascota2 type REF TO z_mascota, amo type REF TO z_amo, descripcion type string. CREATE OBJECT mascota1 EXPORTING i_nombre = 'Pepita'. CREATE OBJECT mascota2 EXPORTING i_nombre = 'Juancito'. CREATE OBJECT amo. SET HANDLER amo->receive FOR ALL INSTANCES. mascota1->jugar( 2 ). descripcion = mascota1->get_string( ). WRITE descripcion.
mascota1->dormir( 4 ). descripcion = mascota1->get_string( ). WRITE: /,descripcion.
mascota1->jugar( 10 ). descripcion = mascota1->get_string( ). WRITE: /,descripcion.
mascota2->jugar( 5 ). descripcion = mascota2->get_string( ). WRITE: /,descripcion.
mascota2->jugar( 5 ). descripcion = mascota2->get_string( ). WRITE: /,descripción. |
Consideraciones adicionales sobre el código ejemplo anterior:
- Notar que la sentencia “SET HANDLER amo->receive FOR ALL INSTANCES” relaciona el objeto amo con el evento CANSADO de ambas mascotas ( mascota1 y mascota2). Ésta es la relación dinámica que se habló al comienzo del artículo. Se podría haber hecho por separado, es decir, dos sentencias SET HANDLER, una para cada mascota o especificar todas las instancias separadas por espacios luego del FOR.
- Ejecutar el programa y verifique que efectivamente el evento es lanzado por cada objeto mascota y manejado por un mismo amo. Perfectamente se podrían haber instanciado dos objetos amo, vinculando uno con la primera mascota y el otro con la segunda.
- Comentar la sentencia SET HANDLER en el programa z y comprobar que en tal caso el evento no es manejado por el amo ya que no se establece la relación dinámica necesaria.
- Ver el código del método JUGAR en la clase Z_MASCOTA. Notar que este es el lugar donde se “levanta” el evento en el caso que la mascota haya jugado en exceso. La sentencia que lo hace posible es “RAISE EVENT cansado”.
Especialista ABAP |
Copyright 2013 - Teknoda S.A.
IMPORTANTE: “Notas técnicas de SAP ABAP" se envía con frecuencia variable y sin cargo como servicio a nuestros clientes SAP. Contiene notas/tutoriales/artículos técnicos desarrollados en forma totalmente objetiva e independiente. Teknoda es una organización de servicios de tecnología informática y NO comercializa hardware, software ni otros productos. |