SAP新BADI

17.3.1.           新式BADI创建

新式BADI中的增强容器Enhancement Spot、BADI定义 BADI Definitions、接口Interface、增强实现Enhancement Implementation、BADI实现BADI Implementation、实现类之间的关系:

一个增强容器下可以创建多个BADI定义,每个BADI定义由一个接口与多个增强实现组成,而每个增强实现里又可以创建多个BADI实现,而每个BADI实现里可以创建一个现实类

17.3.1.1.       定义

 

首先需要创建BADI增强点(Enhancement Spot), Enhancement Spot是作为一个BADI的容器, 在容器里面,我们可以定义自己的多个BADI:

 

 

在新建立的enhancement spot中创建BADI:

定义BADI时,默认采用的是单一使用(single-use),如果没有选中复合使用选项(Multiple Use),单一使用的限制是只能有一个实现

一个Enhancement Spot可以定义多个BADI,每个BADI又是由一个接口与多个实例类组成的。Enhancement Spot相当于容器概念,用来存储多个BADI,而每一个BADI必须定义一个接口,该接口可以有一个或多个实现(增强实现 Enhancement Implementation,每个增强实现里面才能定义实现类),BADI实质上就是将接口与实现类组织(打包、捆绑)在一起了:

 

BADI对象是由接口实现组成的,下面创建BADI接口:

 

双击接口名,可以创建接口,以及定义接口中的方法

17.3.1.2.       实现

由于一个BADI的实现可以有多个类,这些多个实现类需要组织(打包、捆绑)在一起(与多个BADI放在一个Enhancement Spot容器中是一个概念),所以需要创建一个新的BADI增强实现容器ZBADI_DEM001_IMP:

 

 

一个增强实现(Enhancement Implementation)可以有多个BADI Implementations(相当于多个版本每个BADI Implementations即与一个且仅一个实现类对应),但起作用的同时只能有一个,有多个版本时需要进行设置:

 

如果想要达到像Java中多态的话,需要创建多个不同的Enhancement Implementation增强实现,BADI中的多态就是通过不同的Enhancement Implementation增强实现来实现的

 

当有两个增强实现Z_BADI_CALC_IMPL_C、Z_BADI_CALC_IMPL_C2,需要把其中一个的Implementation is active前的钩去掉才能被激活:

 

17.3.1.3.       过滤器

 

 

 

 

注意:上面过滤值一定要大写,否则运行时匹配不到

17.3.1.3.1.              调用

parameters: filter(2) type c.
DATA: handle TYPE REF TO z_badi_calc_vat,"z_badi_calc_vat为BADI定义名,不是接口也不是类
sum TYPE p,
vat TYPE p,
percent TYPE p.
sum = 50.
GET BADI handle
  FILTERS "SE18中定义的过滤器名作为这里的参数名
    filter1 = 'C'.
CALL BADI handle->get_vat
  EXPORTING
    im_amount      = sum
  IMPORTING
    ex_amount_vat  = vat
    ex_percent_vat = percent.

17.3.1.4.       多个BADI/ Enhancement实现时究竟调谁

在同一Enhancement Implementation中(如下图中的Z_BADI_CALC_IMPL_C),不同的BADI Implementations(Z_BADI_CALC_IMPL、Z_BADI_CALC_IMPL2)之间究竟选谁的问题,是 Default ImplementationImplementation is active选项共同来决定的,且在同一时间内只能有一个BADI Implementations能被激活调用,所以要通过这两个选项来控制究竟谁被用来当作当前实现被使用,是否被使用也可通过图中的 Runtime Behavior说明文字来查看:

 

不同的Enhancement Implementation之间(Z_BADI_CALC_IMPL、Z_BADI_CALC_IMPL2)调用由过滤器来决定

 

17.3.2.           经典BADI创建

通过SE18->Utilities->Create Classic BAdi创建经典BADI

 

 

 

 

17.3.2.1.       Filter-Depend.过滤器

当BADI的某个实现版本有多个实现类时,这时在调用时如果想要调用指定的类,则需添加过滤器参数,该参数实质上由其代理类来使用,在运行时代理类会去实例化所对应的类。

 

加上该选项后,接口与实现类中的所有方法都会自动的加上一个必输参数FLT_VAL

 

钩选Filter-Depend选项后,我们再为实现增加过滤值:

 

17.3.2.1.1.              调用

DATA: out TYPE string.
DATA: l_badi_instance TYPE REF TO zif_ex__badidef_baditest2. zif_ex__badidef_baditest2是BAdi Definition的Interface name接口名
CALL METHOD cl_exithandler=>get_instance
  CHANGING instance = l_badi_instance.

IF l_badi_instance IS NOT INITIAL.
  CALL METHOD l_badi_instance->test
    EXPORTING
      "flt_val参数是由l_badi_instance实例来使用的,从这里可以推断l_badi_instance应该属于代理对象,由它在运行时根据过滤器值来选择性的调用相应实现类的方法
      flt_val = '800'
      in      = 'hello'
    CHANGING
      out     = out.
  WRITE: / out.
ENDIF.

17.3.2.2.       通过经典BADI扩展自定义程序(菜单、屏幕、功能)

 

 

 

下面是实现:

 

 

 

 

 

 

 

 

 

DATA: ok_code LIKE sy-ucomm.
DATA: program TYPE program,
      dynpro TYPE dynnr.
DATA: ref_badi_interface TYPE REF TO zif_ex_badi_defined.
CALL SCREEN 100.

MODULE status_0100 OUTPUT.
  SET PF-STATUS '100'.
  IF ref_badi_interface IS INITIAL.
    DATA: act_imp_existing .
    "获取 BADI 的实现 Generated Exit Class
    CALL METHOD cl_exithandler=>get_instance
      EXPORTING
        exit_name              = 'ZBADI_DEFINED'
        "如果未找到BADI实现或有实现但未激活时,ref_badi_interface是否可以接受NULL(即 INITIAL)
        "一般设置为空,在为空时,如果未实现或未激活时,还是会返回一个代理实现,这样后面程序运行不
        "会出错,否则设置为X时,在未实现或未激活时,ref_badi_interface不会有值,则如果通过它调用
        "方法时,会抛异常
        null_instance_accepted = ' '
      IMPORTING
        act_imp_existing       = act_imp_existing "实现是否已激活
      CHANGING
        instance               = ref_badi_interface.
    IF act_imp_existing <> 'X'.
      MESSAGE 'BADI实现没有被激活' TYPE 'I'.
      "EXIT.
    ENDIF.
    CALL METHOD cl_exithandler=>set_instance_for_subscreens
      EXPORTING
        instance = ref_badi_interface.
    "获取BADI实现中所配置的增强子屏幕信息
    CALL METHOD cl_exithandler=>get_prog_and_dynp_for_subscr
      EXPORTING
        exit_name       = 'ZBADI_DEFINED'"BADI 出口名,即BADI定义名
        calling_dynpro  = '0100'"主调屏幕号
        calling_program = 'ZRP_BADITEST'"主调屏幕所属程序
        subscreen_area  = 'SUB_AREA'"主调屏幕中的增强子屏幕区域名
      IMPORTING
        called_dynpro   = dynpro "增强子屏幕号
        called_program  = program."增强子屏幕所属程序
  ENDIF.
ENDMODULE.                 " STATUS_0100  OUTPUT

MODULE user_command_0100 INPUT.
  CASE ok_code.
    WHEN 'FC1'.
      MESSAGE '普通菜单' TYPE 'I'.
      "只要BADI实现激活后,才会出现菜单,即可以点击,才可能走这里的逻辑
    WHEN '+BADI'.
      MESSAGE '增强菜单' TYPE 'I'.
    WHEN 'BUT1'.
      "如果BADI未实现或实现但未激活时,只要 cl_exithandler=>get_instance
      "时,设置输入参数 null_instance_accepted = ' ',ref_badi_interface
      "就会指向一个代理实现类,调用不会抛异常,但只是个空的方法,什么作用
      "也不会有
      CALL METHOD ref_badi_interface->hello.
  ENDCASE.
ENDMODULE.

17.3.3.           示例:通过BADI实现采购订单屏幕增强

主要用到两个BADI:ME_GUI_PO_CUST(屏幕处理)和ME_PROCESS_PO_CUST(业务数据处理)

详细请参考增强相关文档

17.4.     第四代:Enhancement-Point

此种不建议使用,只有无法通过 User Exit与BADI都无法实现时,才考虑这个

第四代其实是第三代上的加强

Ehancement Spot: 用来组织Enhancement options,it's a container of Enhancement options

Enhancement Implementation:用来组织Enhancement options的实现代码

Enhancement Spot是对Enhancement的一个管理平台,Enhancement-Point技术与BADI是有区别的,首先BADI是SAP预留的类的接口,而Enhancement-Point则是允许用户对现有的SAP代码进行修改,例如插入、替换,只要符合一定的规则即可,不需要SAP预先定义好

ENHANCEMENT-POINT是在程序中直接插入代码,其概念与BADI的USER_EXIT类似,标准程序预留了部分已定义好的增强点可以让ABAP做插入代码来实现这个增强(也可以自定义增强点(ENHANCEMENT-POINT),但不能自定义增强选项(ENHANCEMENT-OPTION),增强选项一定是系统预留下来的,如果没有增强选项则该处不可做增强),但是不能做屏幕和菜单增强。

其最大的优势在于方便,可以直接使用程序中所有已定义的变量,不像BADI和USER EXIT中只能使用方法或函数接口传过来看参数

一般增强步骤:

  1. DEBUG标准程序找到需要增强的位置,点EDIT->SHOW IMPLICIT ENHANCEMENT OPTIONS查看是否有预留增强选项。(标准程序不能自己创建enhancement option ,只能使用系统预留的
  2. 创建增强点实现

17.4.1.           为自己程序创建显示增强

 

进入创建增强选项界面,输入增强点名及增强容器名(以Z开头),确认回车。

注:Enhancement Spot 就是SE18中的Enhancement Spot

随后Editor上会多出一条语句,然后转到增强模式

 

 

 

注:Enhancement Spot相当于一个容器,创建一个增强点的必要条件是要有一个容器。每个增强点(如ZENH_POINT_01)都可以创建到这个容器当中,也可以再创建一个容器。删除这个容器的方法:在本地对象或它的包中删除或在SE18中删除

对于ENHANCEMENT-SECTION,定义和实现的方法与ENHANCEMENT-POINT一样。两者的区别是:enhancement-point没有代码,只有一个预留点,允许在这个位置插入新代码(implementation),而nhancement-section和end-enhancement-section.之间有代码,implementation之后,替换旧代码,只执行新代码,原来的代码不再执行

17.4.2.           隐式与显示增强

Implicit enhancements comprise(包含)class enhancements, function group enhancements and predefined enhancement points at particular predefined positions such as the end of a report, a function module, an include or a structure and the beginning and the end of a method。隐式增强就是系统内置的Enhancement options

显式增强就是手动加入到程序中的Enhancement options,有两种显式增强:

ENHANCEMENT-POINT,用来插入新的功能代码,没有代码,只有一个预留点

Defines a position in an ABAP program as an enhancement option, at which one or more source code plug-ins can be inserted.

ENHANCEMENT-POINT enh_id SPOTS spot1 spot2 ...
                   [STATIC]
                   [INCLUDE BOUND].

ENHANCEMENT-SECTION,ENHANCEMENT-SECTION 和 END-ENHANCEMENT-SECTION. 之间有代码, implementation 之后,替换旧代码,只执行新代码,原来的代码不再执行

Defines a section of an ABAP program as an enhancement option, which can can be replaced by one or more source code plug-ins.

ENHANCEMENT-SECTION enh_id SPOTS spot1 spot2 ...
                     [STATIC]
                     [INCLUDE BOUND].
   ...
END-ENHANCEMENT-SECTION.

隐式增强:在 执行程序,包含程序,函数组,对话模块的结尾;Form例程,函数模块,方法等的开始和结尾;结构的结尾这些地方都会有

显示增强:需要在编辑器中创建,可参考上面

原文出自 江正军 技术博客,博客链接:www.cnblogs.com/jiangzhengjun
posted @ 2023-03-30 14:18  kang09  阅读(113)  评论(0编辑  收藏  举报