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 Implementation、Implementation 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中只能使用方法或函数接口传过来看参数
一般增强步骤:
- DEBUG标准程序找到需要增强的位置,点EDIT->SHOW IMPLICIT ENHANCEMENT OPTIONS查看是否有预留增强选项。(标准程序不能自己创建enhancement option ,只能使用系统预留的)
- 创建增强点实现
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例程,函数模块,方法等的开始和结尾;结构的结尾这些地方都会有
显示增强:需要在编辑器中创建,可参考上面