ABAP增强- 第三代:基于类的增强(BADI)

 第三代:基于类的增强(BADI)

BADI维护是通过SE18、SE19事务来来维护的。SE18用于创建及维护BADI对象;SE19用于维护BADI的实例

 

BADI的查找方法:

1、主程序都会调用cl_exitHandler=>get_instance(这只是经典BADI是这样来调用的,如果是新式的BADI,则调用为GET BADI handle-BADI定义名、CALL BADI handle->method)来判断对象是否存在,并返回实例。我们可以在se24中对类cl_exitHandler=>get_instance方法进行调试,运行一个tcode,看一下exit_name的值,这就是要找的BADI

2、在主程序中搜索cl_exitHandler,查看它所引用(TYPE REF TO)的接口名,根据接口命名规则 IF_EX_<badi>,得到<badi>命称

3、通过程序查找

 

命名规则:

Badi definition: Z<badi>

Interface: ZIF_EX_<badi>

BADI implementation:Z<impl>

Implementing class:ZCL_IM_<impl>

image229

新式BADI创建

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

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

 定义

image230

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

image231

image232

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

image233

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

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

image234

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

image235

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

实现

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

image236

image237

image238

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

image239

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

image240

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

image241

过滤器

image242

image243

image244

image245

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

 调用

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.

image246

多个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说明文字来查看:

image247

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

image248

image249

经典BADI创建

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

image250

image251

image252

image253

Filter-Depend.过滤器

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

image254

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

image255

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

image256

调用

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.

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

image257

image258

image259

下面是实现:

image260

image261

image262

 

image263

image264

image265

image266

image267

image268

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.

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

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

详细请参考增强相关文档

 

RIPRO主题是一个优秀的主题,极致后台体验,无插件,集成会员系统
SapiBook » ABAP增强- 第三代:基于类的增强(BADI)

1 评论

  1. Pingback: viagra

发表评论