使用接口

学习目标

  • 使用接口。

接口使用

声明接口参考

可将接口用作声明参考变量的参考类型。如前所述,使用参考变量创建和管理类的实例。由于无法实例化接口,因此您可能想知道可以使用接口参考管理哪些类型的对象。

接口参考可能包含对实施接口的任何类的实例的引用,方法与具有超级类类型的参考变量可以包含对任何子类实例的引用的方式相同。(如果现在假设超类是抽象类,则您有一个相同的类型情况,该情况无法实例化,其中包含对与其相关的其他类实例的引用)。

使用具有超类类型的变量来管理其中一个子类的实例时,只能访问在超类中定义的组件。同样,当您使用接口参考来管理实施接口的类的实例时,只能访问接口中定义的组件。这意味着特定类框架的开发人员可以传送提供特定类视图的接口,而不是公开类可以执行的每个事物。

您可以使用具有类类型 的参考变量从接口调用方法。在这种情况下,必须使用方法的完全限定名称(包括接口名称)。如果已为方法定义别名,则可以使用该别名。使用接口参考调用接口方法时,接口的名称根据参考变量的类型推断,无需在方法名称之前指定接口名称。

含接口参考的构造

将对象参考分配到接口参考也是转换;您将租赁或运输公司对象视为业务伙伴。您始终可以将实施类的实例分配到接口参考。这是向上转换,由类实施接口 来保证。但是,您不能将接口参考中的对象分配给具有实施类的类型的参考,因为语法检查无法判断实际运行时对象是否兼容。如果接口参考中的对象确实是 lcl_car_rental 的实例,则分配 rental = partner 将有效,但如果它是其他实施类的实例,则会导致运行时错误。

在这里,我们有一个下转型的方式,在继承中遇到它。此处的解决方案相同。如果需要将具有接口类型的参考变量中的对象参考分配给具有类类型的对象参考(以便您可以访问类的特定功能),则必须使用 CAST 运算符。在这种情况下,正确的解决方案为:

IF partner IS INSTANCE OF lcl_car_rental.
rental = CAST #( partner ).
ENDIF.

试用:接口使用

  1. 创建实施接口 IF_OO_ADT_CLASSRUN 的新类。

  2. 切换到 局部类型 标签并将以下代码片段复制到编辑器中:

INTERFACE lif_partner.
METHODS get_partner_attributes.
ENDINTERFACE.
CLASS lcl_travel_Agency DEFINITION.
PUBLIC SECTION.
ENDCLASS.
CLASS lcl_airline DEFINITION.
PUBLIC SECTION.
INTERFACES lif_Partner.
TYPES: BEGIN OF ts_detail,
name TYPE string,
value TYPE string,
END OF ts_detail,
tt_Details TYPE SORTED TABLE OF ts_detail WITH UNIQUE KEY name.
METHODS get_details RETURNING VALUE(rt_details) TYPE tt_details.
ENDCLASS.
CLASS lcl_car_Rental DEFINITION.
PUBLIC SECTION.
interfaces lif_Partner.
TYPES: BEGIN OF ts_info,
name TYPE c LENGTH 20,
value TYPE c LENGTH 20,
END OF ts_info,
tt_Info TYPE SORTED TABLE OF ts_info WITH UNIQUE KEY name.
METHODS get_information RETURNING VALUE(rt_details) TYPE tt_info.
ENDCLASS.
CLASS lcl_airline IMPLEMENTATION.
METHOD get_details.
ENDMETHOD.
METHOD lif_partner~get_partner_attributes.
ENDMETHOD.
ENDCLASS.
CLASS lcl_car_rental IMPLEMENTATION.
METHOD get_information.
ENDMETHOD.
METHOD lif_partner~get_partner_attributes.
ENDMETHOD.
ENDCLASS.
  1. 切换到 全局类 标签并将以下代码片段粘贴到方法 if_oo_adt_classrun~main() 的实施中。

CLASS zcl_s4d401_interfaces_2 DEFINITION
PUBLIC
FINAL
CREATE PUBLIC .
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun .
PROTECTED SECTION.
PRIVATE SECTION.
ENDCLASS.
CLASS zcl_s4d401_interfaces_2 IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
DATA car_rental TYPE REF TO lcl_car_rental.
DATA airline TYPE REF TO lcl_airline.
DATA agency TYPE REF TO lcl_travel_agency.
DATA partners TYPE TABLE OF REF TO lif_partner.
agency = NEW #( ).
car_rental = NEW #( iv_name = 'ABAP Autos' iv_contact_person = 'Mr Jones' iv_has_hgv = abap_true ).
agency->add_partner( car_rental ).
airline = NEW #( iv_name = 'Fly Happy' iv_contact_person = 'Ms Meyer' iv_city = 'Frankfurt' ).
agency->add_partner( airline ).
LOOP AT agency->get_partners( ) INTO DATA(partner).
out->write( partner->get_partner_attributes( ) ).
ENDLOOP.
ENDMETHOD.
ENDCLASS.

调用接口方法

在上一练习中,已定义接口 LIF_OUTPUT 并在类 LCL_CARRIERLCL_FLIGHT 中实施该接口。在全局类中,已为创建的载体实例调用 LIF_OUTPUT 接口中的 get_output 方法。在本练习中,现在还将为类 LCL_PASSENGER_FLIGHT 和 L**CL_CARGO_FLIGHT** 的实例调用 get_output 接口方法。

模板:

  • /LRN/CL_S4D401_OOS_INTERFACE(全局类)

解决方案:

  • /LRN/CL_S4D401_OOS_INTF_USAGE(全局类)

任务 1: 复制模板(可选)

复制模板类 /LRN/CL_S4D401_OOS_INTERFACE。如果已完成上一练习,则可以跳过此任务并继续编辑类 ZCL_##_SOLUTION

步骤

  1. 将类 /LRN/CL_S4D401_OOS_INTERFACE 复制到您自己的包中的类(建议名称:ZCL_##_SOLUTION,其中 ## 代表组编号)。

  2. 在项目浏览器中,右键单击类 /LRN/CL_S4D401_OOS_INTERFACE 以打开上下文菜单。

  3. 从上下文菜单中,选择复制....

  4. 在包字段中输入的名称。在名称字段中,输入 ZCL_##_SOLUTION,其中 ## 代表组编号。

  5. 选择下一步

  6. 确认传输请求并选择完成

  7. 激活复制。

  8. Ctrl + F3 激活类。

任务 2: 使用接口

在本地类 LCL_FLIGHT 中,更改实例方法 GET_DESCRIPTION 的可见性,以强制外部用户改为调用方法 GET_OUTPUT。然后相应地调整方法 IF_OO_ADT_CLASSRUN~MAIN 的实施。

步骤

  1. 在局部类 LCL_FLIGHT 中,使用快速修复将实例方法 GET_DESCRIPTION 的可见性更改为**受保护**。

  2. 导航到本地类 LCL_FLIGHT 中方法 GET_DESCRIPTION 的定义。

  3. 在 METHODS 语句中,将光标置于 get_description 上并按 Ctrl + 1 调用可用的快速修复。

  4. 从可用快速修复列表中,选择 使 get_description 受到保护

  5. 在子类 LCL_PASSENGER_FLIGHT 和 L**CL_CARGO_FLIGHT** 中更改 GET_DESCRIPTION 的重新定义可见性。

注意

必须手动复制重新定义。还没有快速修复来更改重新定义的可见性。

  1. 导航到本地类 LCL_PASSENGER_FLIGHT 中方法 GET_DESCRIPTION 的重新定义。

  2. 选择 METHODS 语句,然后按 Ctrl + X

  3. 将光标放在 PROTECTED SECTION 语句之后的下一行中,然后按 Ctrl + V

  4. 在局部类 LCL_CARGO_FLGHT 中重复此操作。

  5. 调整调用方法 GET_DESCRIPTION 的方法 IF_OO_ADT_CLASSRUN~MAIN 的实施。将方法 GET_DESCRIPTION 替换为接口方法 GET_OUTPUT

提示

使用问题视图中的两条错误消息导航到仍调用方法 GET_DESCRIPTION 的位置。

  1. 如下调整代码:

out->write( name = |Found a suitable passenger flight in { days_later } days:|
*              data = pass_flight->get_description( ) ).
data = pass_flight->lif_output~get_output( ) ).
  1. 如下调整代码:

out->write( name = |Found a suitable cargo flight in { days_later2 } days:|
*              data = cargo_flight->get_description( ) ).
data = cargo_flight->lif_output~get_output( ) ).
  1. 为接口方法 LIF_OUTPUT~GET_OUTPUT 定义别名,以便更轻松地调用方法(建议别名:GET_OUTPUT)。

提示

如果在父类 LCL_FLIGHT 中定义别名,则会由两个子类继承。

  1. 导航到本地类 LCL_FLIGHT 的定义。

  2. 如下调整代码:

CLASS lcl_flight DEFINITION ABSTRACT.
PUBLIC SECTION.
INTERFACES lif_output.
ALIASES get_output for lif_output~get_output.
  1. 返回到方法 IF_OO_ADT_CLASSRUN~MAIN 的实施并将 LIF_OUTPUT~GET_OUTPUT 替换为别名。

  2. 如下调整代码:

out->write( name = |Found a suitable passenger flight in { days_later } days:|
*              data = pass_flight->get_description( ) ).
*              data = pass_flight->lif_output~get_output( ) ).
data = pass_flight->get_output( ) ).
  1. 如下调整代码:

out->write( name = |Found a suitable cargo flight in { days_later2 } days:|
*              data = cargo_flight->get_description( ) ).
*              data = cargo_flight->lif_output~get_output( ) ).
data = cargo_flight->get_output( ) ).
  1. 以控制台应用形式激活并测试全局类。

  2. Ctrl + F3

  3. F9