前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >matinal:SAP ABAP OO面向对象编程中的触发和处理事件

matinal:SAP ABAP OO面向对象编程中的触发和处理事件

作者头像
matinal
发布2024-03-20 15:24:23
780
发布2024-03-20 15:24:23
举报
文章被收录于专栏:SAP TechnicalSAP Technical

在ABAP对象中,触发和处理事件意味着某些方法充当触发器并触发事件,其他方法(即处理程序)会对这些事件做出反应。这意味着当事件发生时,处理程序方法会被执行。本文内容介绍了如何在ABAP对象中使用事件(特别说明:本文内容来源SAP 的ABAP编程手册《BC - ABAP Programming》)。

触发事件

要触发一个事件,一个类必须:

  • 在其声明部分声明事件
  • 在其某个方法中触发事件

声明事件

你可以在类的声明部分或接口中声明事件。要声明实例事件,使用以下语句:EVENTS <evt> EXPORTING... VALUE(<ei>) TYPE type [OPTIONAL]。要声明静态事件,使用以下语句:CLASS-EVENTS <evt>... 这两个语句具有相同的语法。

当你声明一个事件时,你可以使用EXPORTING附加项来指定传递给事件处理程序的参数。参数总是按值传递。实例事件总是包含隐式参数SENDER,其类型为引用到声明事件的类型或接口。

触发事件

类的实例事件可以由类中的任何方法触发。静态事件可以由任何静态方法触发。要在方法中触发事件,使用以下语句:RAISE EVENT <evt> EXPORTING... <ei> = <fi>... 对于每个未定义为可选的正式参数<ei>,你必须在EXPORTING附加项中传递相应的实际参数<fi>。自引用ME会自动传递给隐式参数SENDER。

处理事件

事件是通过特殊方法来处理的。要处理一个事件,一个方法必须:

  • 被定义为该事件的事件处理方法
  • 在运行时为该事件注册。

声明事件处理方法

任何类都可以包含来自其他类的事件的处理方法。当然,你也可以在同一类中定义事件本身的事件处理方法。要声明一个事件处理方法,使用以下语句:

METHODS <meth> FOR EVENT <evt> OF <cif> IMPORTING.. <ei>..

对于实例方法。对于静态方法,使用CLASS-METHODS代替METHODS。<evt>是在类或接口<cif>中声明的事件。

事件处理方法的接口只能包含在事件<evt>的声明中定义的正式参数。参数的属性也被事件所采用。事件处理方法不必使用在RAISE EVENT语句中传递的所有参数。如果你想同时使用隐式参数SENDER,你必须在接口中列出它。这个参数允许实例事件处理方法访问触发器,例如,允许它返回结果。

如果你在类中声明了一个事件处理方法,这意味着该类的实例或类本身原则上能够处理在方法中触发的事件<evt>。

注册事件处理方法

要允许事件处理方法对事件做出反应,你必须在运行时确定它要反应的触发器。你可以使用以下语句来实现这一点:

SET HANDLER... <hi> ... [FOR]...

它将一系列处理方法与相应的触发方法链接起来。有四种不同类型的事件。它可以是

  • 在类中声明的实例事件
  • 在接口中声明的实例事件
  • 在类中声明的静态事件
  • 在接口中声明的静态事件 SET HANDLER的语法和效果取决于上述四种情况中的哪一种适用。

对于实例事件,你必须使用FOR附加项来指定你想要注册处理程序的实例。你可以使用引用变量<ref>来指定单个实例作为触发器:

SET HANDLER... <hi> ...FOR <ref>。

或者,你可以为所有可能触发事件的实例注册处理程序:SET HANDLER... <hi>...FOR ALL INSTANCES。这样,即使在注册处理程序时尚未创建触发实例,注册也适用。

你不能为静态事件使用FOR附加项:

SET HANDLER... <hi>...

注册会自动适用于整个类,或者适用于实现包含静态事件的接口的所有类。在接口的情况下,注册也适用于在注册处理程序之后才加载的类。

事件处理的时机

在RAISE EVENT语句之后,所有注册的处理方法会在处理下一条语句之前执行(同步事件处理)。如果处理方法本身触发事件,它的处理方法会在原始处理方法继续之前执行。为了避免无限递归的可能性,目前事件最多只能嵌套64层。

处理方法按照它们注册的顺序执行。由于事件处理程序是动态注册的,你不应该假设它们会按照特定顺序处理。相反,你应该在编程时假设所有事件处理程序将同时执行。

概览图

假设我们有两个类,C1和C2:

类C1包含一个事件E1,该事件由方法M1触发。类C2包含一个方法M2,它可以处理类C1的事件E1。

以下图表说明了处理程序的注册过程:

程序创建了类C1的一个实例和类C2的两个实例。引用变量R1、H1和H2的值指向这些实例。

SET HANDLER语句为每个已注册处理方法的事件创建了一个对用户不可见的处理程序表。

处理程序表包含处理方法的名称和注册实例的引用。表中的条目由SET HANDLER语句动态管理。处理程序表中的实例引用类似于引用变量中的引用。换句话说,它被视为实例的使用,因此直接影响其生命周期。在上面的图表中,这意味着只要它们的注册没有从处理程序表中删除,实例C2<1>和C2<2>就不会被垃圾回收,即使H1和H2已经被初始化。

对于静态事件,系统为相关类创建了一个与实例无关的处理程序表。

当触发事件时,系统会在相应的事件表中查找,并在适当的实例(或对于静态处理方法,在相应类中)执行方法。

事件:入门示例程序

以下简单示例展示了ABAP对象中事件的原理。在类counter中声明并触发了一个名为critical_value的事件。

代码语言:javascript
复制
REPORT zmatinal.

" 定义一个名为counter的类,用于计数器功能。
CLASS counter DEFINITION.
  PUBLIC SECTION.
    " 公开部分,包含可以被其他类访问的方法。
    METHODS increment_counter. " 定义一个方法来增加计数器的值。
    EVENTS critical_value EXPORTING value(excess) TYPE i. " 定义一个事件,当计数器超过临界值时触发。
  PRIVATE SECTION.
    " 私有部分,包含类的内部数据和方法。
    DATA: count TYPE i, " 定义一个整型变量来存储计数器的值。
    threshold TYPE i VALUE 10. " 定义一个整型变量作为计数器的临界值,初始值为10。
ENDCLASS.

" 实现counter类的方法。
CLASS counter IMPLEMENTATION.
  METHOD increment_counter.
    DATA diff TYPE i.
    " 增加计数器的值。(公众号:matinal)
    ADD 1 TO count.
    " 如果计数器的值超过了临界值,触发critical_value事件。
    IF count > threshold.
      diff = count - threshold.
      RAISE EVENT critical_value EXPORTING excess = diff.
    ENDIF.
  ENDMETHOD.
ENDCLASS.

" 定义一个名为handler的类,用于处理counter类的critical_value事件。
CLASS handler DEFINITION.
  PUBLIC SECTION.
    " 公开部分,包含可以被其他类访问的方法。
    METHODS handle_excess
      FOR EVENT critical_value OF counter
      IMPORTING excess. " 定义一个方法来处理counter类的critical_value事件。
  PRIVATE SECTION.
    " 私有部分,包含类的内部数据和方法。
ENDCLASS.

" 实现handler类的方法。
CLASS handler IMPLEMENTATION.
  METHOD handle_excess.
    " 当触发critical_value事件时,输出超过临界值的数量。
    WRITE: / 'Excess is', excess.
  ENDMETHOD.
ENDCLASS.

" 数据声明,用于存储counter和handler类的实例引用。
DATA: r1 TYPE REF TO counter,
      h1 TYPE REF TO handler.

" 程序开始执行时的代码。
START-OF-SELECTION.
  " 创建counter和handler类的实例。
  CREATE OBJECT: r1, h1.
  " 为所有counter类的实例注册handler类的handle_excess方法。
  SET HANDLER h1->handle_excess FOR ALL INSTANCES.
  " 循环20次,每次调用increment_counter方法来增加计数器的值。
  DO 20 TIMES.
    CALL METHOD r1->increment_counter.
  ENDDO.

类COUNTER实现了一个计数器。当超过阈值时,它会触发CRITICAL_VALUE事件并显示差异。HANDLER可以在COUNTER中处理异常。在运行时,处理程序会为所有指向对象的引用变量注册。

上述程序运行结果如下图:

怎么样,在了解此篇文章有何感想?

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2024-03-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档