1, 接口定义
接口(Interfaces) 即可以保证这些类外部看起来具胡一致性,标准化的接口, 又可以在不同的类内部使用不同的实现方法, 而这个具体实现过程是类外部的用户无需关心的.
接口是一个独立结构, 可以在其中定义一些成员并在具体类中实现, 其作用是对类中已经定义的成员进行扩展. 实现接口后,接口将成为类的公有成员, 但类可以自行对接口中的方法以其自身特定形式实现. 这样, 对于用户来说, 不同的类对象包含相同的操作接口(即接口中定义的成员名称), 但程序内部的具体实现则根据类的不同而有所区别. 接口是OOP中除继承之外的另一个主要多态性的实现机制技术.
在程序中定义接口.
1 2 3 4 5 6 | INTERFACE intf. DATA ... CLASS-DATA ... METHOD ... ... ENDINTERFACE. |
在接口定义内部可以声明的成员与类中的成员相同, 但无需注明具体的可见性, 因为具体类中实现的所有接口组件均为公有成员. 同时, 接口定义中也只包含成员声明部分, 而具体的实现也将在具体类中进行.
2, 接口实现
实现接口.
接口没有自己的实例, 因而也不需要进行方法实现, 其中方法的实现要通过具体的类进行.
语法格式如下:
1 2 3 4 5 6 | CLASS class1 DEFINITION. PUBLIC SECTION. ... INTERFACES: int1, int2. ... ENDCLASS. |
在类定义中, 接口的实现只能出现在公有部分, 接口中定义的所有组件都将被添加为该类的公有成员.
接口中的成员通过接口名称 + " ~ " + 成员方式访问. intf~comp.
在类的实现部分, 必须包含所有的接口方法实现.
1 2 3 4 5 6 7 8 9 10 11 | CLASS class IMPLEMENTATION. ... METHOD intf1_imeth1. ... ENDMETHOD. ... METHOD intf2_imeth2. ... ENDMETHOD. ... ENDCLASS. |
一个接口可以被任意多个不同的类实现, 该接口中定义的成员集在各个类中名称相同(形成了一个标准接口), 然而各个类中成员的方法的实现方式则可以有差异, 也就形成了多态性. 如果一个类中除接口之外没有定义任何类自身的公有成员方法, 则接口就成了该类中的全部"外部接口".
3, 接口引用
引用变量是访问 ABAP 对象的途径, 与基于类声明的引用变量类似, 也可以基于接口声明引用变量, 即接口引用. 接口引用也是一种对象引用, 对于包含接口的类对象, 除通过类引用访问之外, 还可通过接口引用进行访问. 接口引用可以指向任何实现了该接口的对象.
1 | YPTES|DATA iref TYPE REF TO intf. |
其中 intf 是全局或程序中已经定义的接口.
通过接口引用访问对象.
要访问一个类对象, 必须先声明一个基于该类的引用变量, 如果该类为一个接口的实现, 则可以将该车胎变量赋给一个接口变量, 此时接口引用与类引用指向相同的类对象.
假设接口变量名称为 inef, 类引用名称为 cref, 赋值语法格式如下:
1 | iref = cref. |
使用类引用访问:
1 2 | cref->intf~attr. CALL METHOD cref->intf~meth. |
使用接口引用访问属性和方法的语法格式如下:
1 2 | iref->attr. CALL METHOD iref->meth. |
对于接口中定义的静态成员, 如果该成员是常量, 则只能通过接口引用进行访问:
1 | intf=>const |
对于其他静态接口成员, 则可以通过实现该接口的类本身或者类引用进行访问:
1 2 | class=>intf~attr. CALL METHOD class=>intf~meth. |
4, 接口引用间赋值
与类引用类似, 可以将接口引用分配给不同的引用变量, 还可以在类引用和接口引用之间相互赋值.
假设存在类引用 cref 和接口引用iref, iref1 和 iref2.
1 | iref1 = iref2. |
系统将进行静态语法检查, 这两个接口必须参照同一个接口声明, 或者 iref2 所参照的接口是接口 iref1 的一个成员.
如果使用形式:
1 | iref = cref. |
则 cref 参照的类必须是 ABAP 预定义的空类 OBJECT.
对于所有其他情况, 则必须通过强制赋值语句或者强制赋值运算符 "?="进行.
1 2 | MOVE iref to cref. cref ?= iref. |
在进行强制赋值时, 系统不会出现任何静态语法检查, 但系统将在运行时检查目标对象引用变量是否可以指向源变量引用的对象. 如果允许则进行赋值, 否则将触发可以捕获的运行时错误 MOVE_CASE_ERROR.
如果将接口引用赋给类引用, 且该类不是参照OBJECT声明,则必须使用强制赋值, 要使赋值过程成功, 接口引用 iref所指向的对象中必须与类引用cref参照的类相同.
5, 例子程序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 | REPORT ztest_oo_interface. *---------------------------------------------------------------------* * INTERFACE if_output *---------------------------------------------------------------------* * *---------------------------------------------------------------------* INTERFACE if_output. METHODS write. ENDINTERFACE. "if_output *---------------------------------------------------------------------* * INTERFACE if_go_zintest *---------------------------------------------------------------------* * *---------------------------------------------------------------------* INTERFACE go_zintest. METHODS test. ENDINTERFACE.
*---------------------------------------------------------------------* * INTERFACE if_status *---------------------------------------------------------------------* * *---------------------------------------------------------------------* INTERFACE if_status. DATA int TYPE i . CLASS-DATA cint TYPE i. METHODS write. CONSTANTS const TYPE i VALUE 30. ENDINTERFACE. "if_status
*&---------------------------------------------------------------------* *& Class cl_superclass *&---------------------------------------------------------------------* * Text *----------------------------------------------------------------------* CLASS cl_superclass DEFINITION. PUBLIC SECTION. INTERFACES :if_output,if_status,go_zintest. METHODS increment. PRIVATE SECTION. DATA count TYPE i. ENDCLASS. "cl_superclass *&---------------------------------------------------------------------* *& Class (Implementation) cl_superclass *&---------------------------------------------------------------------* * Text *----------------------------------------------------------------------* CLASS cl_superclass IMPLEMENTATION. METHOD if_output~write. WRITE / 'Hello SAP'. ENDMETHOD. "if_output~write METHOD if_status~write. WRITE: / 'Count in count is ',count. ENDMETHOD. "if_status~write METHOD go_zintest~test. WRITE: / 'it is the BADI test interface'. ENDMETHOD. "go_zintest~test METHOD increment. ADD 1 TO count. ENDMETHOD. "increment
ENDCLASS. "cl_superclass
DATA:go_super_obj TYPE REF TO cl_superclass, go_super_object TYPE REF TO cl_superclass.
DATA:go_intf_obj TYPE REF TO if_output, "引用接口if_output go_intf_table TYPE TABLE OF REF TO if_output. "引用接口创建内表
DATA:go_interface_obj TYPE REF TO if_status, "引用接口if_status go_interface_table TYPE TABLE OF REF TO if_status. "引用接口创建内表
DATA:go_badi_obj TYPE REF TO go_zintest. "引用接口go_zintest
START-OF-SELECTION. * 实例调用接口方法,类引用 CREATE OBJECT : go_super_obj,go_super_object. CALL METHOD: go_super_obj->if_output~write. SKIP. * 直接调用接口方法,需要通过内表实现,接口引用 APPEND go_super_obj TO go_intf_table. LOOP AT go_intf_table INTO go_intf_obj. CALL METHOD go_intf_obj->write. ENDLOOP.
APPEND go_super_obj TO go_interface_table. LOOP AT go_interface_table INTO go_interface_obj. CALL METHOD go_interface_obj->write. ENDLOOP.
SKIP.
CALL METHOD go_super_obj->increment.
APPEND go_super_obj TO go_interface_table. LOOP AT go_interface_table INTO go_interface_obj. CALL METHOD go_interface_obj->write. ENDLOOP.
SKIP.
* 接口引用赋值类引用 go_interface_obj = go_super_object. CALL METHOD go_interface_obj->write.
go_badi_obj = go_super_object. CALL METHOD go_super_object->go_zintest~test. CALL METHOD go_badi_obj->test.
SKIP.
* 类实例访问变量 go_super_obj->if_status~int = 5. WRITE / go_super_obj->if_status~int. * 类实例访问静态变量 go_super_obj->if_status~cint = 10. WRITE / go_super_obj->if_status~cint. * 类名访问静态变量 cl_superclass=>if_status~cint = 20. WRITE / cl_superclass=>if_status~cint . * 接口实例访问变量 go_interface_obj->int = 5. WRITE / go_interface_obj->int. * 接口实例访问静态变量 go_interface_obj->cint = 10. WRITE / go_interface_obj->cint. * 接口名访问常量 WRITE / if_status=>const. |
运行结果: