事件 练习

事件 练习

#practice #events #oo-events #abap-objects

📌核心模式 (点击展开)
关键词 答案
实例事件定义 EVENTS evt_name [EXPORTING ...]
静态事件定义 CLASS-EVENTS evt_name [EXPORTING ...]
触发事件 RAISE EVENT evt_name
注册处理程序 SET HANDLER handler->on_event FOR instance
SENDER 参数 自动传递的发送者引用

题目1 - 事件定义关键字 [记忆]

在 ABAP Objects 中,定义实例事件和静态事件分别使用哪两个关键字?

📌查看答案
  • 实例事件:使用 EVENTS 关键字定义
  • 静态事件:使用 CLASS-EVENTS 关键字定义

语法示例:

1
2
3
4
5
6
7
CLASS lcl_example DEFINITION.
PUBLIC SECTION.
EVENTS: data_changed " 实例事件
EXPORTING VALUE(e_data) TYPE string.
CLASS-EVENTS: status_update " 静态事件
EXPORTING VALUE(e_status) TYPE char1.
ENDCLASS.

实例事件绑定到具体对象实例,静态事件属于类本身,不依赖实例即可触发和监听。


题目2 - RAISE EVENT 语法 [记忆]

如何在类的方法中触发(raise)一个事件?请写出基本语法,并说明实例事件和静态事件的触发有何区别。

📌查看答案
使用 RAISE EVENT 语句触发事件:
1
2
3
4
RAISE EVENT evt_name
EXPORTING
e_param1 = value1
e_param2 = value2.

区别说明:

  • 实例事件:在实例方法中使用 RAISE EVENT 触发。也可在静态方法中触发同一类的实例事件(但实际不推荐,因为静态方法没有明确的实例上下文)。
  • 静态事件:可在实例方法或静态方法中使用 RAISE EVENT 触发。

注意:触发事件时,EXPORTING 参数必须与事件定义中的参数匹配。


题目3 - 事件处理程序注册 [记忆]

写出 SET HANDLER 的三种注册形式,并解释每种形式的适用场景。

📌查看答案
三种 SET HANDLER 注册形式:
  1. 为特定实例注册

    1
    SET HANDLER handler->on_event FOR obj.

    只监听对象 obj 触发的事件。

  2. 为所有实例注册

    1
    SET HANDLER handler->on_event FOR ALL INSTANCES.

    监听该类所有现有和未来创建的实例触发的事件。

  3. 为静态事件注册

    1
    SET HANDLER handler->on_event.

    不需要指定 FOR,因为静态事件不绑定到实例。

注意:如果不再需要监听,使用 SET HANDLER handler->on_event FOR obj ACTIVATION space. 取消注册。


题目4 - 事件处理方法定义 [记忆]

事件处理方法(handler method)的定义语法是什么?它与普通方法在参数声明上有什么特殊限制?

📌查看答案
事件处理方法使用 FOR EVENT 语法定义:
1
2
3
METHODS on_data_changed
FOR EVENT data_changed OF lcl_sender
IMPORTING sender e_data.

特殊限制:

  • 处理方法的参数只能 IMPORTING(不能有 EXPORTING、CHANGING、RETURNING)
  • 参数列表必须与事件定义的 EXPORTING 参数匹配
  • SENDER 是一个隐式可用的参数,代表触发事件的对象引用,类型为触发事件的类引用
  • 即使事件没有定义参数,处理方法仍可声明 IMPORTING sender

题目5 - SENDER 参数的作用 [记忆]

在事件处理方法中,SENDER 参数的作用是什么?它是如何传递的?

📌查看答案
SENDER 参数的作用
  • SENDER 是事件处理方法中的一个隐式可用参数
  • 它持有触发事件的对象实例的引用
  • 类型为触发事件所在类的对象引用
  • 通过 SENDER,处理方法可以访问触发者的公共属性和方法

传递机制

  • SENDER 不需要在事件的 EXPORTING 列表中显式声明
  • 它由 ABAP 运行时环境自动传递
  • 处理方法可以自由选择是否在 IMPORTING 中声明使用 SENDER
1
2
3
METHODS on_event
FOR EVENT data_changed OF lcl_source
IMPORTING sender e_data. " sender 可选声明

题目6 - 事件参数传递方向分析 [分析]

为什么事件处理方法(handler method)只能有 IMPORTING 参数,而不能有 EXPORTING 或 RETURNING?请从事件机制的通信模型角度分析原因。

📌查看答案
这与事件的 一对多广播通信模型 有关:
  1. 一对多关系:一个事件可以有多个处理程序(handler)。如果允许处理方法返回值或输出参数,系统无法确定应该将哪个处理程序的返回值传递回触发者。

  2. 解耦设计:事件机制的核心是触发者不需要知道谁在监听。如果处理方法能向触发者传回数据,就打破了这种单向通信的解耦。

  3. 异步语义:触发者发出事件后继续执行,不等待处理结果。如果需要双向通信,应使用直接方法调用而非事件。

如果确实需要在处理方法中改变数据,可以通过引用传递已有对象(在事件参数中传递对象引用),处理方法修改该对象的状态。


题目7 - 完整事件流程编写 [应用]

请根据以下需求编写完整的 ABAP 代码:

  • lcl_timer 有一个静态事件 timeout,导出参数 e_seconds TYPE i
  • lcl_display 有处理方法 on_timeout,接收 e_seconds 并写入 WRITE 输出
  • 在启动程序中注册处理程序并触发事件
📌查看答案
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
CLASS lcl_timer DEFINITION.
PUBLIC SECTION.
CLASS-EVENTS timeout
EXPORTING VALUE(e_seconds) TYPE i.
CLASS-METHODS: start
IMPORTING iv_seconds TYPE i.
ENDCLASS.

CLASS lcl_timer IMPLEMENTATION.
METHOD start.
RAISE EVENT timeout EXPORTING e_seconds = iv_seconds.
ENDMETHOD.
ENDCLASS.

CLASS lcl_display DEFINITION.
PUBLIC SECTION.
METHODS on_timeout
FOR EVENT timeout OF lcl_timer
IMPORTING e_seconds.
ENDCLASS.

CLASS lcl_display IMPLEMENTATION.
METHOD on_timeout.
WRITE: / '超时!', e_seconds, '秒已过'.
ENDMETHOD.
ENDCLASS.

" 启动程序
START-OF-SELECTION.
DATA(lo_display) = NEW lcl_display( ).
SET HANDLER lo_display->on_timeout. " 静态事件无需 FOR
lcl_timer=>start( iv_seconds = 30 ).

题目8 - 事件与实例生命周期 [应用]

假设你有一个类 lcl_document,每当文档状态改变时触发事件 status_changed。多个监听者(logger、notifier)需要监听此事件。当文档对象被删除后,注册的处理程序会发生什么?如何安全地管理事件注册的生命周期?

📌查看答案
1
2
3
4
5
6
7
" 事件定义
CLASS lcl_document DEFINITION.
PUBLIC SECTION.
EVENTS status_changed
EXPORTING VALUE(e_new_status) TYPE char10.
METHODS: change_status.
ENDCLASS.

生命周期管理要点

  1. 垃圾回收机制:当文档对象被删除(没有引用指向它)后,ABAP 垃圾回收器会自动清除与该实例相关的事件注册。

  2. 显式取消注册:最佳实践是在不再需要监听时显式取消注册:

    1
    2
    SET HANDLER lo_logger->on_status_changed
    FOR lo_document ACTIVATION space.
  3. 内存泄漏风险:如果使用 FOR ALL INSTANCES 注册且处理程序对象生命周期很长,可能导致不必要的监听。应确保在适当时机取消注册。

  4. 安全模式:建议在处理程序类中提供 register( )unregister( ) 方法封装 SET HANDLER 逻辑,在 cleanup 方法中统一取消所有注册。


📌模式总结 (点击展开)
关键词 答案
实例事件 EVENTS 关键字定义,绑定到对象实例
静态事件 CLASS-EVENTS 关键字定义,属于类级别
触发事件 RAISE EVENT evt_name EXPORTING ...
注册-指定实例 SET HANDLER h FOR obj
注册-所有实例 SET HANDLER h FOR ALL INSTANCES
注册-静态事件 SET HANDLER h(无 FOR 子句)
取消注册 SET HANDLER ... ACTIVATION space
处理方法定义 FOR EVENT evt OF cls IMPORTING ...
处理方法限制 只能有 IMPORTING 参数
SENDER 隐式传递的触发者对象引用
一对多模型 一个事件可有多个处理程序
生命周期 对象删除后注册自动失效