Using Interfaces

Objective

After completing this lesson, you will be able to Use Interfaces.

Interface Use

Declaring an Interface Reference

You can use interfaces as a reference type for declaring a reference variable. As you learned earlier, you use reference variables to create and manage instances of a class. Since it is not possible to instantiate an interface, you may be wondering what kinds of objects you can manage using an interface reference.

Interface references may contain references to instances of any class that implements the interface in the same way that a reference variable with the type of a superclass can contain references to any subclasses. (If you now imagine that the superclass is abstract, you have an identical situation of a type that cannot be instantiated holding references to other classes that are related to it).

When you use a variable with the type of a superclass to manage an instance of one of its subclasses, you can only access the components that are defined in the superclass. Similiarly, when you use an interface reference to manage an instance of a class that implements the interface, you can only access the components that are defined in the interface. This means that the developer of a particular framework of classes can ship interfaces that provide a particular view of an object instead of exposing every single thing that the class can do.

You can call a method from an interface using a reference variable with the type of the class. In this case, you must use the fully-qualified name of the method (including the interface name). If you have defined an alias for the method, you can use that. When you call an interface method using an interface reference, the name of the interface is inferred from the type of the reference variable, and you do not need to specify the interface name before the method name.

Casting with Interface References

Assigning object references to an interface reference is also a cast; you look at the rental or carrier object as though it were a business partner. You can always assign an instance of the implementing class to an interface reference. This is an up-cast, and is guaranteed by the fact that the class implements the interface. You cannot, however, assign an object from an interface reference to a reference with the type of an implementing class, since the syntax check cannot tell whether the actual runtime objects will be compatible. The assignment go_rental = go_partner would work if the object in the interface reference really is an instance of lcl_rental, but if it is an instance of another implementing class, you would cause a runtime error.

Here we have a down-cast in the same way that we encountered it in inheritance. The solution here is the same. If you need to assign an object reference from a reference variable with the type of an interface to one with the type of a class (so that you can access specific features of the class), you must use the CAST operator. The correct solution in this case would be:

Code Snippet
Copy code
Switch to dark mode
12345
IF partner IS INSTANCE OF lcl_car_rental. rental = CAST #( partner ). ENDIF.

Try it Out: Interface Use

  1. Create a new class that implements the interface IF_OO_ADT_CLASSRUN.
  2. Switch to the Local Types tab and copy the following code snippet into the editor:
    Code Snippet
    Copy code
    Switch to dark mode
    123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
    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.
  3. Switch to the Global Class tab and paste the following code snippet into the implementation of method if_oo_adt_classrun~main( ).
    Code Snippet
    Copy code
    Switch to dark mode
    12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849
    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.

Work with Interface References

You make use of interface LIF_OUTPUT by typing reference variables with this interface.

Template:

  • /LRN/CL_S4D401_OOS_INTERFACE (Global Class)

Solution:

  • /LRN/CL_S4D401_OOS_INTF_USAGE (Global Class)

Task 1: Copy Template (Optional)

Copy the template class. If you finished the previous exercise, you can skip this task and continue editing your class ZCL_##_SOLUTION.

Steps

  1. Copy class /LRN/CL_S4D401_OOS_INTERFACE to a class in your own package (suggested name: ZCL_##_SOLUTION, where ## stands for your group number).

    1. In the Project Explorer view, right-click class /LRN/CL_S4D401_OOS_INTERFACE to open the context menu.

    2. From the context menu, choose Duplicate ....

    3. Enter the name of your package in the Package field. In the Name field, enter the name ZCL_##_SOLUTION, where ## stands for your group number.

    4. Adjust the description and choose Next.

    5. Confirm the transport request and choose Finish.

  2. Activate the copy.

    1. Press Ctrl + F3 to activate the class.

Task 2: Use the Interface

In local class LCL_FLIGHT, change the visibility of instance method GET_DETAILS to force external users to call method GET_OUTPUT, instead. Then adjust the implementation of method IF_OO_ADT_CLASSRUN~MAIN accordingly.

Steps

  1. In local class LCL_FLIGHT, use a quick fix to change the visibility of instance method GET_DETAILS to protected.

    1. Navigate to the definition of method GET_DESCRIPTION in local class LCL_FLIGHT.

    2. In the METHODS statement, place the cursor on get_description and press Ctrl + 1 to invoke the quick fix.

    3. From the list of available quick fixes, choose Make get_description protected.

  2. Change the visibility of the redefinitions of GET_DETAILS in the subclasses LCL_PASSENGER_FLIGHT and LCL_CARGO_FLIGHT.

    Note

    You have to copy the redefinitions manually, There is no quick fix yet to change the visibility of redefinitions.
    1. Navigate to the redefinition of method GET_DESCRIPTION in local class LCL_PASSENGER_FLIGHT.

    2. Select the METHODS statement and press Ctrl + X.

    3. Place the cursor in the next row after the PROTECTED SECTION statement and press Ctrl + V.

    4. Repeat this in local class LCL_CARGO_FLGHT.

  3. Adjust the implementation of method IF_OO_ADT_CLASSRUN~MAIN where method GET_DESCRIPTION is called. Replace method GET_DESCRIPTION with interface method GET_OUTPUT.

    Hint

    Use the two error messages on the Problems view to navigate to the places where method GET_DESCRIPTION is still called.
    1. Adjust the code as follows:

      Code Snippet
      Copy code
      Switch to dark mode
      123
      out->write( name = |Found a suitable passenger flight in { days_later } days:| * data = pass_flight->get_description( ) ).
    2. Adjust the code as follows:

      Code Snippet
      Copy code
      Switch to dark mode
      123
      out->write( name = |Found a suitable cargo flight in { days_later2 } days:| * data = cargo_flight->get_description( ) ).
  4. Define an alias for interface method LIF_OUTPUT~GET_OUTPUT to make calling the method easier (Suggested alias name: GET_OUTPUT).

    Hint

    If you define the alias in superclass LCL_FLIGHT it is inherited by the two subclasses.
    1. Navigate to the definition of local class LCL_FLIGHT.

    2. Adjust the code as follows:

      Code Snippet
      Copy code
      Switch to dark mode
      1234
      CLASS lcl_flight DEFINITION ABSTRACT. PUBLIC SECTION. INTERFACES lif_output.
  5. Return to the implementation of method IF_OO_ADT_CLASSRUN~MAIN and replace LIF_OUTPUT~GET_OUTPUT with the alias.

    1. Adjust the code as follows:

      Code Snippet
      Copy code
      Switch to dark mode
      1234
      out->write( name = |Found a suitable passenger flight in { days_later } days:| * data = pass_flight->get_description( ) ). * data = pass_flight->lif_output~get_output( ) ).
    2. Adjust the code as follows:

      Code Snippet
      Copy code
      Switch to dark mode
      1234
      out->write( name = |Found a suitable cargo flight in { days_later2 } days:| * data = cargo_flight->get_description( ) ). * data = cargo_flight->lif_output~get_output( ) ).
  6. Activate and test your global class as console app.

    1. Press Ctrl + F3.

    2. Press F9.

Log in to track your progress & complete quizzes