定义接口

学习目标

  • 定义接口。

接口定义

使用接口的原因

使用接口可以定义程序如何处理一个或多个类。在接口中,可以像在类中一样定义方法、属性、类型和常量。这些组件构成了客户端程序如何与相应对象进行交互的描述。但是,接口无法实例化,并且不包含其方法的任何实施。要使概念生效,还需要一个或多个实施接口的类。这意味着它们在其自己的类声明中包括接口,在接口中声明的组件将成为类本身的一部分。如果接口包含方法声明,则实施接口的类还必须提供该方法的实施。

接口有两个重要用途:

为不同的类提供统一的方法:如果您的类与继承无关,但仍应向其用户提供通用服务,则可以在接口中定义通用服务。这可确保每个类都提供具有相同名称和相同签名的方法,以执行特定任务。然后,无论实际寻址哪个类,使用类的程序都可以通过单一方式调用特定功能。

提供复杂类的简化方法:如稍后所述,接口提供对象的受限视图。这使您可以向程序公开一组特定的方法,该程序将根据程序实际需要的功能使用特定类。

观看此示例以了解接口的工作方式。

视频:本节含 SAP 官方视频(视频 ID 1_zaqhaatl),需在 learning.sap.com 在线观看。

接口定义

接口的定义与类的定义部分非常相似。但是,由于接口没有实施,INTERFACE 语句中没有 DEFINITION 附加项。第二个主要区别是接口中没有可见性部分,因为接口的所有组件都是公共的。接口由于其与其他类的交互而有用,因此具有非公共组件没有意义。

在接口定义中,您可以使用类型、属性、常量和方法,并允许实例和静态组件。请记住,接口方法具有定义,但没有实施。这将由实施类提供。

在许多方面,接口类似于抽象超级类。对于需要定义类的通用组件而无需继承的情况(即没有明确的"是"关系),它们提供了一种有用的技术。

实施接口

要在类中实施接口,请使用 INTERFACES 语句。由于接口的所有组件都是公共的,并且您无法更改现有组件的可见性,因此必须在类的公共部分中包含该接口。

一旦您编写了 INTERFACES 语句,程序就会出现语法错误。这是因为接口包含尚未实施的方法。您可以使用快速修复 (Ctrl + 1) 将方法实施添加到类。

在类中声明接口时,必须实现其所有方法。

在类的实现中,必须实施在接口中声明的所有方法。对实施中的方法进行命名时,必须使用完全限定名称,该名称由接口名称和由波浪符连接的方法名称组成。这是因为无法保证方法名称本身是明确的;请记住,组件名称只有在声明它们的类或接口中才能唯一。因此,类可以声明名为 get_partner_attributes 的方法以及接口 lif_partner。

试用:接口定义

  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. 按 Ctrl + F3 激活类。

  2. 熟悉代码。

注意

此示例中没有可执行代码。

定义和实施接口

您意识到局部类 LCL_CARRIER 中的方法 GET_OUTPUT 和本地类 LCL_FLIGHT 中的方法 GET_DESCRIPTION 非常相似。为了协调定义,引入接口并在两个类中实施。

模板:

  • /LRN/CL_S4D401_OOS_INH_USAGE(全局类)

解决方案:

  • /LRN/CL_S4D401_OOS_INTERFACE(全局类)

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

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

步骤

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

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

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

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

  5. 选择下一步

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

  7. 激活复制。

  8. Ctrl + F3 激活类。

任务 2: 定义接口

定义局部接口(建议名称:LIF_OUTPUT)并在局部类 LCL_FLIGHTLCL_CARRIER 中实施。

注意

暂时将接口留空。我们将在下一任务中添加接口组件。

步骤

  1. 在全局类中,导航到本地类 LCL_FLIGHT 的定义。

  2. 例如,在 大纲 视图上选择类名称。

  3. 在公共部分,添加声明实现尚不存在的接口 LIF_OUTPUT 的语句。

  4. 如下调整代码:

CLASS lcl_flight DEFINITION ABSTRACT.
PUBLIC SECTION.
INTERFACES lif_output.
  1. 使用快速修复将接口 LIF_OUTPUT 创建为本地接口。

  2. 在 INTERFACES 语句中,将光标放在 lif_output 上,然后按 Ctrl + 1 调用可用的快速修复。

  3. 从可用快速修复列表中,选择创建本地接口 lif_output

结果

快速修复会生成以下代码:

INTERFACE lif_output.
ENDINTERFACE.
  1. 也可以在本地类 LCL_CARRIER 中实施新接口。

  2. 导航到本地类 LCL_CARRIER 的定义。

  3. 在 PUBLIC SECTION 语句下方添加以下代码:

INTERFACES lif_output.

任务 3: 实施接口方法

将实例方法 GET_OUTPUT 的定义从类 LCL_CARRIER 移动到接口 LIF_OUTPUT。然后在本地类 LCL_FLIGHT 中实施接口,在其中将请求委托给方法 GET_DESCRIPTION

步骤

  1. 使用快速修复将(拉取)方法 GET_OUTPUT 从本地类 LCL_CARRIER 移动到本地接口 LIF_OUTPUT

注意

忽略有关方法引用该类的其它组件的警告。

  1. 在局部类 LCL_CARRIER 中,导航到实例方法 GET_OUTPUT 的定义。

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

  3. 从可用快速修复列表中,选择 Pull-Up get_output 到接口 lif_output

  4. 仔细阅读警告,然后选择 继续

结果

快速修复将从 LCL_CARRIER 类中删除 GET_OUTPUT 方法的定义,并将该方法添加到接口:

INTERFACE lif_output.
METHODS get_output
RETURNING VALUE(r_result) TYPE tt_output.
ENDINTERFACE.

此外, LCL_CARRIER 类的实施部分中的方法名称已调整为接口方法的完全限定名称:

METHOD lif_output~get_output.
APPEND |{ 'Carrier Name:'(001)       } { me->name }| TO r_result.
APPEND |{ 'Passenger Flights:'(002)  } { pf_count }| TO r_result.
APPEND |{ 'Average free seats:'(003) } { get_average_free_seats(  ) }| TO r_result.
APPEND |{ 'Cargo Flights:'(004)      } { cf_count }| TO r_result.
ENDMETHOD.

最后,快速修复在 LCL_CARRIER 类的公共部分为接口方法 lif_output~get_output 创建别名 get_ output:

ALIASES: get_output FOR lif_output~get_output.
  1. 问题 视图中分析新的语法错误。

  2. 打开位于编辑器下方的 问题 视图。

  3. 使用快速辅助将类型 TT_OUTPUTT_OUTPUT 从本地类 LCL_CARRIER 移动到接口 LIF_OUTPUT

  4. 在局部类 LCL_CARRIER 中,导航到类型 TT_OUTPUT 的定义。

  5. 在 TYPES 语句中,将光标放在 tt_output 上,然后按 Ctrl + 1 调用可用的快速修复。

  6. 从可用快速修复列表中,选择 Pull-Up tt_output 到接口 lif_output

  7. 选择继续以忽略与类型 T_OUTPUT 相关的警告。

  8. 重复上述步骤以将类型 T_OUTPUT 拉取到接口。

  9. 如有必要,在接口定义中调整类型 TT_OUTPUTT_OUTPUT 的顺序。

  10. 接口定义应如下所示:

INTERFACE lif_output.
TYPES t_output  TYPE string.
TYPES tt_output TYPE STANDARD TABLE OF t_output
WITH NON-UNIQUE DEFAULT KEY.
METHODS get_output
RETURNING
VALUE(r_result) TYPE tt_output.
ENDINTERFACE.
  1. 使用快速修复在本地类 LCL_FLIGHT 中添加接口方法 GET_OUTPUT 的缺失实施。

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

  3. 在 INTERFACES 语句中,将光标置于 lif_output 上并按 Ctrl + 1。或者,选择代码行左侧带有灯泡的错误图标。

  4. 从快速修复列表中,选择添加实施 get_output

  5. 在添加的方法 lif_output~get_output 中,执行实例方法 get_description 的调用并将结果存储在返回参数 r_result 中。

  6. 如下调整代码:

METHOD lif_output~get_output.
r_result = get_description( ).
ENDMETHOD.
  1. 以控制台应用形式激活并测试全局类。

  2. Ctrl + F3

  3. F9