事件

事件 (★★★)

#abap-objects #event #event-handler

概览表

项目 关键点
事件定义 EVENTS / CLASS-EVENTS,只有 EXPORTING 参数
触发事件 RAISE EVENT
处理器 FOR EVENT ... OF 方法定义
注册 SET HANDLER ... FOR

事件的概念

事件代表了与显式方法调用完全不同的编程模型

1
2
3
显式调用:                          事件控制:
调用者 ──知道──→ 被调用者 触发者 ──不知道──→ 处理者
(编译时确定) (运行时确定)

核心区别

特性 显式方法调用 事件控制调用
谁决定调用 调用者 触发者
谁定义协议 被调用者(方法签名) 触发者(事件参数)
编译时绑定 知道对方 不知道处理者
数量 一个调用者 可能有零到多个处理者
⚠️不要混淆
不要将OO事件与ABAP运行时事件(LOAD-OF-PROGRAM, START-OF-SELECTION)或后台处理/工作流控制混淆。

定义和触发事件

定义事件

1
2
3
4
5
6
7
8
9
CLASS lcl_vehicle DEFINITION.
PUBLIC SECTION.
" 实例事件
EVENTS: vehicle_created
EXPORTING VALUE(iv_make) TYPE string.

" 静态事件
CLASS-EVENTS: all_vehicles_cleared.
ENDCLASS.

规则:

  • 事件只能有 EXPORTING 参数,必须值传递 (VALUE(...))
  • 实例事件用 EVENTS,静态事件用 CLASS-EVENTS
  • 事件也可以在接口中定义

触发事件

1
2
3
4
5
METHOD constructor.
" ... 初始化 ...
RAISE EVENT vehicle_created
EXPORTING iv_make = mv_make.
ENDMETHOD.

规则:

  • 实例方法中可以触发实例事件和静态事件
  • 静态方法中只能触发静态事件
  • 触发事件后,所有注册的处理方法按不确定的顺序被调用

定义事件处理器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
CLASS lcl_rental DEFINITION.
PUBLIC SECTION.
METHODS: on_vehicle_created
FOR EVENT vehicle_created OF lcl_vehicle
IMPORTING !iv_make
!sender. " 预定义参数 SENDER
ENDCLASS.

CLASS lcl_rental IMPLEMENTATION.
METHOD on_vehicle_created.
" sender 指向触发事件的对象
" iv_make 包含事件传递的数据
APPEND sender TO mt_vehicles.
ENDMETHOD.
ENDCLASS.

处理器规则:

  • FOR EVENT evt OF class — 指定事件和定义事件的类
  • 处理器参数 = 事件的 EXPORTING 参数 (用 IMPORTING 接收)
  • SENDER 是预定义隐式参数,类型为 REF TO 触发事件的类
  • 处理器也可以被显式调用 (CALL METHOD handler)

注册事件处理

1
2
3
4
5
6
7
8
9
10
11
12
" 注册特定实例的事件
SET HANDLER lo_rental->on_vehicle_created
FOR lo_vehicle.

" 注册所有实例的事件
SET HANDLER lo_rental->on_vehicle_created
FOR ALL INSTANCES.

" 取消注册
SET HANDLER lo_rental->on_vehicle_created
FOR lo_vehicle
ACTIVATION space.

注册方式对比

方式 语法 说明
特定实例 FOR ref 只响应指定对象的事件
所有实例 FOR ALL INSTANCES 响应所有对象的事件(包括尚未创建的)
静态事件 不需要 FOR 静态事件不需要指定对象
⚠️事件处理器调用顺序不确定
多个处理器注册到同一事件时,调用顺序不保证!不能依赖处理器的执行顺序。

事件处理流程

1
2
3
4
5
6
1. 定义事件 (在触发类中)
2. 定义处理器 (在处理类中)
3. 注册处理 (SET HANDLER ... FOR ...)
4. 触发事件 (RAISE EVENT)
5. 运行时调用已注册的处理器
6. 可选: 取消注册 (ACTIVATION space)

事件在接口中

1
2
3
4
5
6
7
8
9
10
11
INTERFACE lif_observable.
EVENTS: state_changed
EXPORTING VALUE(iv_state) TYPE string.
ENDINTERFACE.

" 实现接口的类自动拥有该事件
CLASS lcl_subject DEFINITION.
PUBLIC SECTION.
INTERFACES: lif_observable.
" 可以触发 lif_observable~state_changed
ENDCLASS.

考试/测试模式

场景/关键词 答案
“事件参数方向” 只有 EXPORTING,必须值传递
“处理器用什么接收” IMPORTING
“SENDER是什么” 指向触发事件的对象的预定义参数
“调用顺序保证吗” 不保证
“FOR ALL INSTANCES” 注册到所有实例(含未创建的)
“如何取消注册” SET HANDLER ... ACTIVATION space
“静态方法能触发实例事件吗” 不能,只能触发静态事件