Diesen Artikel habe ich ursprünglich im SAP Community Network veröffentlicht.

In den vergangenen ABAP-Fallen-Blogs habe ich über verschiedene Probleme geschrieben, die beim Schreiben von Code in ABAP auftreten können. Beim heutigen Thema geht es eher um ein strukturelles oder gestalterisches Problem. Für dieses Beispiel verwenden wir die folgende Klassenhierarchie:

IMPORTING

Stellen Sie sich eine Methode vor, die eine Instanz von CL_SUPER verwendet, um eine beliebige Operation auszuführen:

METHODS bar
  IMPORTING ir_object TYPE REF TO cl_super.

...

DATA: lr_super TYPE REF TO cl_super,
      lr_sub1  TYPE REF TO cl_sub1,
      lr_sub2  TYPE REF TO cl_sub2.

...

lr_foo->bar( lr_super ).
lr_foo->bar( lr_sub1 ).
lr_foo->bar( lr_sub2 ).

Das ist ziemlich einfach – wenn wir diese Methode aufrufen, können wir entweder eine Variable von TYPE REF TO cl_super oder eine beliebige der Unterklassen übergeben, da jede Instanz von CL_SUB1 eine CL_SUPER-Instanz ist. Dies gilt auch für Unterklassen, von denen der Ersteller der ursprünglichen Klassen nichts weiß – zum Beispiel für alle Kundenimplementierungen, die das bestehende Framework erweitern.

EXPORTING

Für Methoden, die EXPORTING-Parameter bereitstellen, gilt ein etwas anderes Muster:

METHODS bar   
  EXPORTING er_object TYPE REF TO cl_super.   

...   

DATA: lr_super  TYPE REF TO cl_super,   
      lr_root   TYPE REF TO cl_root,   
      lr_object TYPE REF TO object.   

...   

  lr_foo->bar( IMPORTING er_object = lr_super ).   
  lr_foo->bar( IMPORTING er_object = lr_root ).   
  lr_foo->bar( IMPORTING er_object = lr_object ).  

In diesem Fall ist der statische Typ der Variablen, die das exportierte Objekt empfängt, von Bedeutung: Es kann sich um einen TYPE REF TO cl_super oder eine seiner Oberklassen handeln.

CHANGING

Sie haben es vielleicht schon erraten – für einen CHANGING-Parameter müssen Sie die Einschränkungen beachten, die für IMPORTING-Parameter gelten, sowie die, die für EXPORTING-Parameter gelten – mit anderen Worten, Sie können nur den genauen Typ verwenden, der von der Methode angegeben wird. Sie können keinen Supertyp verwenden, da dies gegen die Anforderung verstoßen würde, dass jedes an die Methode übergebene Objekt mindestens der durch CL_SUPER vorgegebenen Struktur entspricht, und Sie können auch keinen Subtyp verwenden, da die Methode nicht garantiert, dass sie etwas Spezifischeres als einen Verweis auf CL_SUPER zurückgibt.

Warum überhaupt CHANGING?

Jetzt lehne ich mich in diesem Fall vielleicht ein wenig aus dem Fenster, aber ich denke, dass in vielen Fällen, in denen CHANGING-Parameter für Objektreferenzen verwendet werden, diese eigentlich unnötig sind und wahrscheinlich nur aufgrund eines Missverständnisses verwendet werden. Nur um es klarzustellen: Um den Zustands eines Objekts zu ändern, muss es nicht als CHANGING-Parameter übergeben werden. Das gilt auch das Gegenteil: Um den Zustand eines Objekts für die Methode, an die Sie es übergeben, unveränderlich zu machen, reicht es nicht aus, es als „IMPORTING“-Parameter zu deklarieren.

Lassen Sie uns dies etwas näher untersuchen.

METHODs print   
  IMPORTING ir_person TYPE REF TO cl_person.   

...   

METHOD print.   

  DATA: l_name TYPE string,   
        lr_nobody TYPE REF TO cl_person.   

  l_name = ir_person-> get_name( ).   
  WRITE: / 'Name:', l_name.   

* Die Referenz selbst zu ändern ist verboten:   
  CREATE OBJECT lr_nobody   
    EXPORTING i_name = 'Ann Onymous'.   
  ir_person = lr_nobody. " <--- SYNTAX ERROR  

* aber das Ändern des Status des übergebenen Objekts ist erlaubt:   
  ir_person->set_name( 'John Doe' ).   

ENDMETHOD.

Das Ausmaß des Problems

Aus Neugier habe ich ein zufälliges System überprüft und über 12.000 Parameter geschützt‚er und öffentlicher Methoden gefunden, die CHANGING-Referenzparameter verwenden – also habe ich tiefer gegraben. Folgendes habe ich gefunden: