ABAP OO - Interface (DEFAULT IGNORE)
In diesem Artikel geht es um die Entwicklung eines Interface mit dem Zusatz DEFAULT und die Konsequenzen auf Implementierung und Nutzung.
Inhaltsverzeichnis
Beim Schreiben des Artikels für die Exits in Application Jobs, sind wir auf ein Konstrukt gestoßen, welches wir bisher noch nicht gesehen haben. Unsere Eindrücke und Arbeit mit solchen Interfaces wollen wir heute mit dir teilen und durch die Einzelheiten der Implementierung gehen.
Einleitung
Um was geht es in diesem Artikel genau? Interfaces sind normalerweise so definiert, dass der Verwender alle Methoden in seinem Coding implementieren muss, ansonsten kann die Klasse nicht aktiviert werden. Das sorgt unter Umständen dafür, dass man 20 Methoden anlegt, man selbst aber eigentlich nur eine Methode implementieren möchte. Dazu wurde bei der Methodendefinition der Zusatz DEFAULT eingeführt, auf den wir in diesem Artikel eingehen wollen.
Interface
Dazu definieren wir uns ein gemischtes Interface, wo alle Arten von Methoden definiert sind. Wir verwenden eine normale Methode, für die wir später eine Implementierung benötigen, zwei Methoden mit DEFAULT IGNORE und eine Methode mit DEFAULT FAIL. Das Interface ist wie folgt definiert:
INTERFACE zif_bs_demo_intf_default
PUBLIC.
METHODS:
method_with_implementation
IMPORTING id_value TYPE string
RETURNING VALUE(rd_result) TYPE abap_bool,
method_with_default_bool DEFAULT IGNORE
IMPORTING id_value TYPE string
RETURNING VALUE(rd_result) TYPE abap_bool,
method_with_default_integer DEFAULT IGNORE
IMPORTING id_value TYPE string
RETURNING VALUE(rd_result) TYPE i,
method_with_fail DEFAULT FAIL
IMPORTING id_value TYPE string
RETURNING VALUE(rd_result) TYPE abap_bool.
ENDINTERFACE.
Für den Zusatz DEFAULT gibt es zwei Erweiterungen:
- IGNORE - Ist die Methode nicht implementiert, dann verhält sich die Implementierung wie eine leere Methodenimplementierung (initiale Parameter).
- FAIL - Ist die Methode nicht implementiert und wird aufgerufen, dann wird eine Ausnahme (CX_SY_DYN_CALL_ILLEGAL_METHOD) ausgelöst, aber erst wenn auch ein Aufruf erfolgt.
Implementierung
Im nächsten Schritt wollen wir einmal die Standardimplementierung des Interfaces testen und legen dazu eine ausführbare Klasse an und implementieren das Interface. Dazu geben wir im Wizard die beiden Interfaces mit an:
Die Klasse wird standardmäßig mit allen Methoden erstellt, damit implementiert der Wizard automatisch auch Methoden die als DEFAULT markiert sind:
CLASS zcl_bs_demo_intf_default DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun.
INTERFACES zif_bs_demo_intf_default.
ENDCLASS.
CLASS zcl_bs_demo_intf_default IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
ENDMETHOD.
METHOD zif_bs_demo_intf_default~method_with_default_bool.
ENDMETHOD.
METHOD zif_bs_demo_intf_default~method_with_default_integer.
ENDMETHOD.
METHOD zif_bs_demo_intf_default~method_with_fail.
ENDMETHOD.
METHOD zif_bs_demo_intf_default~method_with_implementation.
ENDMETHOD.
ENDCLASS.
Zum Testen löschen wir nun alle Methoden aus unserem Interface und versuchen diese über den "Quick Fix" (STRG + 1) wieder zu implementieren, dabei fällt auf, dass dieses mal nur unsere Pflichtmethode angelegt wird:
Der Quick Fix funktioniert für die anderen Methoden nicht und die weiteren Methoden müssen von Hand implementiert werden.
Testcode
Implementieren wir nun erst einmal unseren Testcode, um die Klasse zu testen. Dazu legen wir das folgende Coding in der Main Methode an, um die Funktionalität der einzelnen Methoden ohne Implementierung zu validieren.
DATA lo_test TYPE REF TO zif_bs_demo_intf_default.
lo_test = NEW zcl_bs_demo_intf_default( ).
out->write( |Normal implementation: { lo_test->method_with_implementation( `Normal` ) }| ).
out->write( |Default with Bool: { lo_test->method_with_default_bool( `Default` ) }| ).
out->write( |Default with Integer: { lo_test->method_with_default_integer( `Default` ) }| ).
TRY.
out->write( |Default to Fail: { lo_test->method_with_fail( `Fail` ) }| ).
CATCH cx_sy_dyn_call_illegal_method.
out->write( `Method failed` ).
ENDTRY.
Die Pflichtmethode implementieren wir entsprechend und geben ABAP_TRUE zurück, um ein Ergebnis zu erhalten. Die gesamte Klasse sieht zu diesem Zeitpunkt wie folgt aus:
CLASS zcl_bs_demo_intf_default DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun.
INTERFACES zif_bs_demo_intf_default.
ENDCLASS.
CLASS zcl_bs_demo_intf_default IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
DATA lo_test TYPE REF TO zif_bs_demo_intf_default.
lo_test = NEW zcl_bs_demo_intf_default( ).
out->write( |Normal implementation: { lo_test->method_with_implementation( `Normal` ) }| ).
out->write( |Default with Bool: { lo_test->method_with_default_bool( `Default` ) }| ).
out->write( |Default with Integer: { lo_test->method_with_default_integer( `Default` ) }| ).
TRY.
out->write( |Default to Fail: { lo_test->method_with_fail( `Fail` ) }| ).
CATCH cx_sy_dyn_call_illegal_method.
out->write( `Method failed` ).
ENDTRY.
ENDMETHOD.
METHOD zif_bs_demo_intf_default~method_with_implementation.
rd_result = abap_true.
ENDMETHOD.
ENDCLASS.
Ausführung
Führen wir nun einmal die Klasse im aktuellen Zustand aus und schauen uns das Ergebnis an. Da es sich um eine ausführbare Klasse handelt, können wir diese mit F9 starten und uns das Ergebnis in der Konsole ausgeben lassen.
Wie zu erwarten wurden die ersten drei Methoden ausgeführt und die letzte Methode ist auf Fehler gelaufen, hier gibt es keine Ausgabe, da eine Ausnahme erzeugt wurde. Die beiden Methoden mit DEFAULT IGNORE haben entsprechend initiale Rückgabewerte geliefert und sind erfolgreich durchlaufen worden.
FAIL
Zum Abschluss implementieren wir zum Test noch die Methode mit DEFAULT FAIL, legen die Methode an und geben ABAP_TRUE zurück.
METHOD zif_bs_demo_intf_default~method_with_fail.
rd_result = abap_true.
ENDMETHOD.
Die Methode sollte nun sauber durchlaufen werden und keine Ausnahme mehr auslösen. Nach Ausführung der Klasse erhalten wir das folgende Ergebnis, so wie wir es auch erwartet haben:
Komplettes Beispiel
Zum Abschluss noch die komplette Implementierung der Klasse, das Interface findest du im oberen Bereich des Artikels.
CLASS zcl_bs_demo_intf_default DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun.
INTERFACES zif_bs_demo_intf_default.
ENDCLASS.
CLASS zcl_bs_demo_intf_default IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
DATA lo_test TYPE REF TO zif_bs_demo_intf_default.
lo_test = NEW zcl_bs_demo_intf_default( ).
out->write( |Normal implementation: { lo_test->method_with_implementation( `Normal` ) }| ).
out->write( |Default with Bool: { lo_test->method_with_default_bool( `Default` ) }| ).
out->write( |Default with Integer: { lo_test->method_with_default_integer( `Default` ) }| ).
TRY.
out->write( |Default to Fail: { lo_test->method_with_fail( `Fail` ) }| ).
CATCH cx_sy_dyn_call_illegal_method.
out->write( `Method failed` ).
ENDTRY.
ENDMETHOD.
METHOD zif_bs_demo_intf_default~method_with_implementation.
rd_result = abap_true.
ENDMETHOD.
METHOD zif_bs_demo_intf_default~method_with_fail.
rd_result = abap_true.
ENDMETHOD.
ENDCLASS.
Fazit
Die Nutzung war für uns neu, vielleicht sogar für dich? Der Artikel soll dir dabei helfen, zu verstehen was damit möglich ist. Laut Dokumentation wird es vor allem im Bereich der BADIs zum Einsatz kommen, aber auch freigegebene Objekte von SAP werden damit ausgestattet sein.
Quellen:
SAP-Help - Methods DEFAULT