Code analysieren und testen
Korrekte Verwendung von Datentypen und Typkonvertierungen
Verarbeitung von Zeichenfeldern
Code-Pushdown in ABAP SQL verwenden
Performance interner Tabellen verbessern
Implementieren von Berechtigungsprüfungen
Effektiven objektorientierten Code entwerfen
Ausnahmeklassen definieren und mit Ausnahmeklassen arbeiten
Dokumentation zum ABAP-Quelltext hinzufügen

Einsatz von Interfaces

Objective

After completing this lesson, you will be able to verwenden Sie Schnittstellen.

Schnittstellenverwendung

Interface-Referenz deklarieren

Sie können Interfaces als Referenztyp verwenden, um eine Referenzvariable zu deklarieren. Wie Sie bereits wissen, können Sie mit Referenzvariablen Instanzen einer Klasse anlegen und verwalten. Da ein Interface nicht instanziiert werden kann, fragen Sie sich vielleicht, welche Arten von Objekten Sie mit einer Interface-Referenz verwalten können.

Interfacereferenzen können Referenzen auf Instanzen beliebiger Klassen enthalten, die das Interface implementieren, so wie eine Referenzvariable vom Typ einer Oberklasse Referenzen auf Instanzen beliebiger Unterklassen enthalten kann. (Wenn Sie sich nun vorstellen, dass die Oberklasse abstrakt ist, haben Sie eine identische Situation eines Typs, der nicht instanziiert werden kann und Referenzen auf Instanzen anderer Klassen enthält, die sich darauf beziehen.)

Wenn Sie eine Variable vom Typ einer Oberklasse verwenden, um eine Instanz einer der dazugehörigen Unterklassen zu verwalten, können Sie nur auf die Komponenten zugreifen, die in der Oberklasse definiert sind. Analog dazu: Wenn Sie eine Interface-Referenz verwenden, um eine Instanz einer Klasse zu instanziieren, die das Interface implementiert, können Sie nur auf die Komponenten zugreifen, die im Interface definiert sind. Das bedeutet, dass der Entwickler eines bestimmten Frameworks von Klassen Interfaces ausliefern kann, die eine bestimmte Sicht auf eine Klasse bereitstellen, anstatt jedes einzelne Ding zu exponieren, das die Klasse tun kann.

Sie können eine Interface-Methode aufrufen, indem Sie eine Referenzvariable vom Typ der Klasse verwenden. In diesem Fall müssen Sie den vollqualifizierten Namen der Methode (einschließlich des Interface-Namens) verwenden. Wenn Sie einen Alias für die Methode definiert haben, können Sie diesen verwenden. Wenn Sie eine Interface-Methode über eine Interface-Referenz aufrufen, wird der Interface-Name vom Typ der Referenzvariable abgeleitet. Sie müssen Sie den Interface-Namen nicht vor dem Methodennamen angeben.

Casting bei Interface-Referenzen

Die Zuweisung von Objektreferenzen zu einer Interface-Reference ist ebenfalls ein Cast. Das Miet- oder Fluggesellschaft-Objekt wird als Geschäftspartner gesehen. Sie können einer Interface-Referenz jederzeit eine Instanz der implementierenden Klasse zuweisen. Dies ist ein Up Cast und er wird dadurch gesichert, dass die Klasse das Interface implementiert. Sie können aber kein Objekt aus einer Interface-Referenz zu einer Referenz mit dem Typ einer implementierenden Klasse zuweisen, da die Syntaxprüfung nicht weiß, ob die tatsächlichen Laufzeitobjekte kompatibel sind. Die Zuordnung rental = partner würde funktionieren, wenn das Objekt in der Interface-Referenz tatsächlich eine Instanz von lcl_car_hire ist, aber wenn es sich um eine Instanz einer anderen implementierenden Klasse handelt, würden Sie einen Laufzeitfehler verursachen.

Hier liegt ein Down Cast vor, genau wie bei der Vererbung. Die Lösung ist hier die gleiche. Wenn Sie eine Objektreferenz aus einer Referenzvariablen vom Typ eines Interfaces einer Objektreferenz vom Typ einer Klasse zuweisen müssen (um auf bestimmte Merkmale der Klasse zugreifen zu können), müssen Sie den CAST-Operator verwenden. Die richtige Lösung wäre in diesem Fall:

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

Probieren Sie es aus: Schnittstellennutzung

  1. Legen Sie eine neue Klasse an, die das Interface IF_OO_ADT_CLASSRUN implementiert.
  2. Wechseln Sie zur Registerkarte Lokale Typen, und kopieren Sie den folgenden Code-Snippet in den Editor:
    Code Snippet
    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. Wechseln Sie zur Registerkarte "Globale Klasse", und fügen Sie das folgende Code-Snippet in die Implementierung der Methode if_oo_adt_classrun~main( ) ein.
    Code Snippet
    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.

Interface-Methoden aufrufen

In der vorherigen Übung haben Sie das Interface LIF_OUTPUT definiert und in den Klassen LCL_CARRIER und LCL_FLIGHT implementiert. In Ihrer globalen Klasse wird für die erzeugte Trägerinstanz bereits die Methode get_output aus dem Interface LIF_OUTPUT aufgerufen. In dieser Übung rufen Sie nun auch die Interface-Methode get_output für die Instanzen der Klassen LCL_PASSENGER_FLIGHT und LCL_CARGO_FLIGHT auf.

Vorlage:

  • /LRN/CL_S4D401_OOS_INTERFACE (globale Klasse)

Lösung:

  • /LRN/CL_S4D401_OOS_INTF_USAGE (globale Klasse)

Aufgabe 1: Vorlage kopieren (optional)

Kopieren Sie die Vorlagenklasse /LRN/CL_S4D401_OOS_INTERFACE. Wenn Sie die vorherige Übung abgeschlossen haben, können Sie diese Aufgabe überspringen und mit der Bearbeitung Ihrer Klasse ZCL_##_SOLUTION fortfahren.

Schritte

  1. Kopieren Sie die Klasse /LRN/CL_S4D401_OOS_INTERFACE in eine Klasse in Ihrem eigenen Paket (Namensvorschlag: ZCL_##_SOLUTION, wobei ## für Ihre Gruppennummer steht).

    1. Klicken Sie im Project Explorer mit der rechten Maustaste auf die Klasse /LRN/CL_S4D401_OOS_INTERFACE, um das Kontextmenü zu öffnen.

    2. Wählen Sie im Kontextmenü Duplizieren....

    3. Geben Sie den Namen Ihres Pakets in das Feld Package ein. Geben Sie im Feld NameZCL_##_SOLUTION ein, wobei ## für Ihre Gruppennummer steht.

    4. Wählen Sie Next.

    5. Bestätigen Sie den Transportauftrag, und wählen Sie Finish.

  2. Aktivieren Sie die Kopie.

    1. Drücken Sie Strg + F3, um die Klasse zu aktivieren.

Aufgabe 2: Schnittstelle verwenden

Ändern Sie in der lokalen Klasse LCL_FLIGHT die Sichtbarkeit der Instanzmethode GET_DESCRIPTION, um zu erzwingen, dass externe Benutzer stattdessen die Methode GET_OUTPUT aufrufen. Passen Sie anschließend die Implementierung der Methode IF_OO_ADT_CLASSRUN~MAIN entsprechend an.

Schritte

  1. Verwenden Sie in der lokalen Klasse LCL_FLIGHT eine Schnellkorrektur, um die Sichtbarkeit der Instanzmethode GET_DESCRIPTION in protected zu ändern.

    1. Navigieren Sie zur Definition der Methode GET_DESCRIPTION in der lokalen Klasse LCL_FLIGHT.

    2. Platzieren Sie in der METHODS-Anweisung den Cursor auf get_description, und drücken Sie Strg + 1, um die verfügbaren Quickfixes aufzurufen.

    3. Wählen Sie aus der Liste der verfügbaren Quickfixes die Option Make get_description protected.

  2. Ändern Sie die Sichtbarkeit der Redefinitionen von GET_DESCRIPTION in den Unterklassen LCL_PASSENGER_FLIGHT und LCL_CARGO_FLIGHT.

    Notiz

    Sie müssen die Redefinitionen manuell kopieren. Es gibt noch keine Schnellkorrektur, um die Sichtbarkeit von Neudefinitionen zu ändern.
    1. Navigieren Sie zur Redefinition der Methode GET_DESCRIPTION in der lokalen Klasse LCL_PASSENGER_FLIGHT.

    2. Markieren Sie die Anweisung METHODS, und drücken Sie Strg + X.

    3. Positionieren Sie den Cursor in der nächsten Zeile nach der Anweisung PROTECTED SECTION, und drücken Sie Strg + V.

    4. Wiederholen Sie dies in der lokalen Klasse LCL_CARGO_FLGHT.

  3. Passen Sie die Implementierung der Methode IF_OO_ADT_CLASSRUN~MAIN an, in der die Methode GET_DESCRIPTION aufgerufen wird. Ersetzen Sie die Methode GET_DESCRIPTION durch die Interface-Methode GET_OUTPUT.

    Hinweis

    Verwenden Sie die beiden Fehlermeldungen auf der View Problems, um zu den Stellen zu navigieren, an denen die Methode GET_DESCRIPTION noch aufgerufen wird.
    1. Passen Sie den Quelltext wie folgt an:

      ABAP
      123
      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. Passen Sie den Quelltext wie folgt an:

      ABAP
      123
      out->write( name = |Found a suitable cargo flight in { days_later2 } days:| * data = cargo_flight->get_description( ) ). data = cargo_flight->lif_output~get_output( ) ).
  4. Definieren Sie einen Alias für die Interface-Methode LIF_OUTPUT~GET_OUTPUT, um den Aufruf der Methode zu erleichtern (vorgeschlagener Aliasname: GET_OUTPUT).

    Hinweis

    Wenn Sie den Alias in der Oberklasse LCL_FLIGHT definieren, wird er von den beiden Unterklassen geerbt.
    1. Navigieren Sie zur Definition der lokalen Klasse LCL_FLIGHT.

    2. Passen Sie den Quelltext wie folgt an:

      ABAP
      1234
      CLASS lcl_flight DEFINITION ABSTRACT. PUBLIC SECTION. INTERFACES lif_output. ALIASES get_output for lif_output~get_output.
  5. Kehren Sie zur Implementierung der Methode IF_OO_ADT_CLASSRUN~MAIN zurück, und ersetzen Sie LIF_OUTPUT~GET_OUTPUT durch den Alias.

    1. Passen Sie den Quelltext wie folgt an:

      ABAP
      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( ) ). data = pass_flight->get_output( ) ).
    2. Passen Sie den Quelltext wie folgt an:

      ABAP
      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( ) ). data = cargo_flight->get_output( ) ).
  6. Aktivieren und testen Sie Ihre globale Klasse als Konsolen-App.

    1. Drücken Sie Strg + F3.

    2. Drücken Sie F9.