ABAP - Objekte prüfen (Instanzen)
In diesem Artikel zeigen wir dir, wie du Instanzen analysieren und auf diese korrekt reagieren kannst, wenn du diese zum Beispiel bei einer Verarbeitung übergibst und individuell reagieren möchtest.
Inhaltsverzeichnis
Nicht immer kannst du davon ausgehen, dass deine Methodenschnittstelle korrekt versorgt wird, vor allem wenn du einen generischen Objekttypen zulässt. Für solche Fälle gibt es zwei neue Befehle, die dir das Arbeiten mit Instanzen etwas leichter machen sollen.
Klassenmodell
Für die heutigen Beispiele implementieren wir einige Klassen und Interfaces in Hierarchie, um so die Funktionsweise der beiden neuen Befehle zu demonstrieren. Dazu im ersten Schritt das Datenmodell, basierend auf der abstrakten Klasse LCL_VEHICLE und den entsprechend erbenden Klassen.
Die zweite Testreihe basiert auf einem Interface und den beiden implementierenden Klassen. Die Tiere implementieren das entsprechende Interface und die Methode.
Für die oben gezeigten Hierarchien hier noch die entsprechende minimale Definition in ABAP. Dabei verwenden wir zur Ausgabe das übergebene Objekt des Class Runners.
*** Class and interface definitions
CLASS lcl_vehicle DEFINITION ABSTRACT.
PUBLIC SECTION.
METHODS:
speed_up
IMPORTING
io_output TYPE REF TO if_oo_adt_classrun_out.
ENDCLASS.
CLASS lcl_car DEFINITION INHERITING FROM lcl_vehicle.
PUBLIC SECTION.
METHODS:
open_luggage_space
IMPORTING
io_output TYPE REF TO if_oo_adt_classrun_out.
ENDCLASS.
CLASS lcl_bwm DEFINITION INHERITING FROM lcl_car.
ENDCLASS.
CLASS lcl_truck DEFINITION INHERITING FROM lcl_vehicle.
PUBLIC SECTION.
METHODS:
open_bedroom
IMPORTING
io_output TYPE REF TO if_oo_adt_classrun_out.
ENDCLASS.
CLASS lcl_man DEFINITION INHERITING FROM lcl_truck.
ENDCLASS.
CLASS lcl_plane DEFINITION INHERITING FROM lcl_vehicle.
ENDCLASS.
INTERFACE lif_animal.
METHODS:
make_sound
IMPORTING
io_output TYPE REF TO if_oo_adt_classrun_out.
ENDINTERFACE.
CLASS lcl_cat DEFINITION.
PUBLIC SECTION.
INTERFACES: lif_animal.
ENDCLASS.
CLASS lcl_dog DEFINITION.
PUBLIC SECTION.
INTERFACES: lif_animal.
ENDCLASS.
*** Implementations of the classes
CLASS lcl_car IMPLEMENTATION.
METHOD open_luggage_space.
io_output->write( 'I am opening the luggage space.' ).
ENDMETHOD.
ENDCLASS.
CLASS lcl_truck IMPLEMENTATION.
METHOD open_bedroom.
io_output->write( 'I am opening the bedroom.' ).
ENDMETHOD.
ENDCLASS.
CLASS lcl_cat IMPLEMENTATION.
METHOD lif_animal~make_sound.
io_output->write( 'Miou!' ).
ENDMETHOD.
ENDCLASS.
CLASS lcl_dog IMPLEMENTATION.
METHOD lif_animal~make_sound.
io_output->write( 'Wuff!' ).
ENDMETHOD.
ENDCLASS.
CLASS lcl_vehicle IMPLEMENTATION.
METHOD speed_up.
io_output->write( 'Over 9000!' ).
ENDMETHOD.
ENDCLASS.
IS INSTANCE OF
Der Befehl prüft ein übergebenes Objekt (darf nicht Initial sein), ob es den Type einer Klasse oder eines Interfaces implementiert. Dies funktioniert auch über der Hierarchie der Objekte korrekt. Damit ist sichergestellt, dass die Methoden und Attribute der geprüften Klasse beim Objekt verfügbar sind. Du kannst den Befehl aber auch nutzen, um deine Fehlerbehandlung zu implementieren.
DATA(lo_bwm) = NEW lcl_bwm( ).
IF lo_bwm IS NOT INSTANCE OF lcl_vehicle.
" Error handling
ENDIF.
Im oberen Beispiel haben wir eine Instanz der Klasse LCL_BWM erzeugt, dies kann genau so ein Übergabeparameter in eine Methode sein. Im nächsten Schritt wirde geprüft, ob das Objekt zur abstrakten Klasse LCL_VEHICLE gehört. Sollte dies nicht der Fall sein, kann eine entsprechende Fehlerbehandlung implementiert werden.
CASE TYPE OF
Bei diesem neuen Befehl handelt es sich um einen CASE mit einigen Besonderheiten und soweit für Instanzen optimiert. Hier kannst du eine Objektreferenz (nicht Initial) gegen verschiedene Typen (Klassen und Interfaces) prüfen und darauf reagieren. Dies eignet sich besonders gut, wenn du in einer Verarbeitung auf jedes beliebige Objekt reagieren möchtest. In diesem Fall stellen wir eine Methode zur Verfügung, die alle Arten von Objekten aufnehmen kann.
METHODS:
react_for_different_objects
IMPORTING
io_object TYPE REF TO object
io_output TYPE REF TO if_oo_adt_classrun_out
RAISING
cx_sy_conversion_unknown_unit.
Dieser Methode kannst du dann alle Arten von Objekten übergeben und diese Methode reagiert entsprechend auf den übergebenen Typ.
METHOD react_for_different_objects.
CASE TYPE OF io_object.
WHEN TYPE lif_animal INTO DATA(lo_animal).
lo_animal->make_sound( io_output ).
WHEN TYPE lcl_car INTO DATA(lo_car).
lo_car->open_luggage_space( io_output ).
WHEN TYPE lcl_truck INTO DATA(lo_truck).
lo_truck->open_bedroom( io_output ).
WHEN TYPE lcl_vehicle INTO DATA(lo_vehicle).
lo_vehicle->speed_up( io_output ).
WHEN OTHERS.
RAISE EXCEPTION NEW cx_sy_conversion_unknown_unit( ).
ENDCASE.
ENDMETHOD.
Mit dem Zusatz INTO erzeugst du eine Instanz vom Vergleichstyp im Hintergrund mit einem CAST. Damit hast du dann die Möglichkeit, direkt auf Attribute und Methoden zugrifen zu können (wie im Beispiel oben). Damit kann zum Beispiel eine weitere Verarbeitung angestoßen werden.
Beispiel
An dieser Stelle noch das vollständige Beispiel der Klasse mit der Main- und Testmethode. Die Ausgaben der Meldungen erfolgt über die Console in Eclipse.
CLASS zcl_bs_demo_instance DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun.
PROTECTED SECTION.
PRIVATE SECTION.
METHODS:
react_for_different_objects
IMPORTING
io_object TYPE REF TO object
io_output TYPE REF TO if_oo_adt_classrun_out
RAISING
cx_sy_conversion_unknown_unit.
ENDCLASS.
CLASS zcl_bs_demo_instance IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
DATA(lo_bwm) = NEW lcl_bwm( ).
IF lo_bwm IS INSTANCE OF lcl_vehicle.
out->write( 'LO_BMW is instance from object LCL_VEHICLE' ).
ENDIF.
DATA(lo_dog) = NEW lcl_dog( ).
IF lo_dog IS INSTANCE OF lif_animal.
out->write( 'LO_DOG is instance from interface LIF_ANIMAL' ).
ENDIF.
react_for_different_objects( io_output = out io_object = NEW lcl_car( ) ).
react_for_different_objects( io_output = out io_object = NEW lcl_truck( ) ).
react_for_different_objects( io_output = out io_object = NEW lcl_bwm( ) ).
react_for_different_objects( io_output = out io_object = NEW lcl_man( ) ).
react_for_different_objects( io_output = out io_object = NEW lcl_plane( ) ).
react_for_different_objects( io_output = out io_object = NEW lcl_dog( ) ).
react_for_different_objects( io_output = out io_object = NEW lcl_cat( ) ).
ENDMETHOD.
METHOD react_for_different_objects.
CASE TYPE OF io_object.
WHEN TYPE lif_animal INTO DATA(lo_animal).
lo_animal->make_sound( io_output ).
WHEN TYPE lcl_car INTO DATA(lo_car).
lo_car->open_luggage_space( io_output ).
WHEN TYPE lcl_truck INTO DATA(lo_truck).
lo_truck->open_bedroom( io_output ).
WHEN TYPE lcl_vehicle INTO DATA(lo_vehicle).
lo_vehicle->speed_up( io_output ).
WHEN OTHERS.
RAISE EXCEPTION NEW cx_sy_conversion_unknown_unit( ).
ENDCASE.
ENDMETHOD.
ENDCLASS.
Das erzeugte Ergebnis aus dem Lauf der Klasse sieht dann wie folgt aus. Die entsprechenden Zweige in der REACT Methode wurden durchlaufen:
Fazit
Ein Arbeiten mit generischen Objekten muss nicht immer schwer sein. Mit den beiden neuen Befehlen kannst du leicht das richtige Objekt herausfiltern und validieren und entsprechend darauf reagieren. In der Zukunft erhalten deine Programme etwas mehr Stabilität und Zuverlässigkeit.
Quellen:
SAP Dokumentation - IS INSTANCE OF
SAP Dokumentation - CASE TYPE OF