Ärger mit statischen Objekt-Konstruktoren – Vererbung statischer Eigenschaften in ABAP

Statische Objekt-Konstruktoren können eingesetzt werden, um eine statische Verarbeitung bei der Instanziierung von Objekten einer Klasse zu ermöglichen, wie beispielsweise beim Singleton-Pattern. In der Regel werden diese unter dem Namen “getInstance” implementiert.

Ärger mit diesen Konstruktoren kann man in Sprachen bekommen, die statische Eigenschaften einer Klasse vererben. Folgendes Beispiel in ABAP verdeutlicht das Problem.

ABAP Klasse: zcl_superclass
CLASS ZCL_SUPERCLASS DEFINITION
  PUBLIC
  CREATE PROTECTED.

  PUBLIC SECTION.
    CLASS-METHODS get_instance
        RETURNING VALUE(ro_object) TYPE REF TO zcl_superclass.

    METHODS to_string
        RETURNING VALUE(rv_string) TYPE string.

  PROTECTED SECTION.
    METHODS constructor
        IMPORTING iv_string TYPE string.

  PRIVATE SECTION.
    DATA mv_string TYPE string.

ENDCLASS.


CLASS ZCL_SUPERCLASS IMPLEMENTATION.

  METHOD constructor.
    me->mv_string = iv_string.
  ENDMETHOD.

  METHOD get_instance.
    CREATE OBJECT ro_object EXPORTING iv_string = 'Super class'.
  ENDMETHOD.

  METHOD to_string.
    rv_string = me->mv_string.
  ENDMETHOD.

ENDCLASS.

Die Klasse zcl_superclass ist von außen nicht mit dem normalen Konstruktor instanziierbar, denn der Konstruktor hat die Sichtbarkeit “protected”. Stattdessen kann sie über den statischen Aufruf “get_instance” instanziiert werden. Beim Aufruf von “to_string” auf einem Objekt, gibt dieses den im Konstruktor übergebenen String zurück.

ABAP Klasse: zcl_subclass
CLASS ZCL_SUBCLASS DEFINITION
  INHERITING FROM zcl_superclass
  PUBLIC
  CREATE PUBLIC.

  PUBLIC SECTION.
    METHODS constructor.

ENDCLASS.


CLASS ZCL_SUBCLASS IMPLEMENTATION.

  METHOD CONSTRUCTOR.
    super->constructor( iv_string = 'Sub class' ).
  ENDMETHOD.

ENDCLASS.

Die Klasse zcl_subclass erbt von zcl_superclass, implementiert einen public-Konstruktor und gibt einen festgelegten Text an den Superklassen-Konstruktor mit, sodass der Konstruktor von zcl_subclass keinen Übergabeparameter hat.

Da in ABAP statische Eigenschaften (Methoden und Daten) vererbt werden, ist die Methode “get_instance” mit dem definierten Importing-Parameter auf zcl_subclass zugreifbar.

Konkret bedeutet das, dass es folgende Möglichkeiten der Instanziierung über zcl_subclass gibt.

ABAP Programm: Instanziierungen über zcl_subclass
DATA lv_text TYPE string.

" Korrekte Instanziierung
DATA lo_subclass_object TYPE REF TO zcl_subclass.
CREATE OBJECT lo_subclass_object.
lv_text = lo_subclass_object->to_string( ).

" Falsche Instanziierung
lv_text = zcl_subclass=>get_instance( iv_string = 'Some text' )->to_string( ).

Die zuerst gezeigte Implementierung zeigt das erwartete Verhalten von zcl_subclass, d. h. lv_text nimmt den Wert “Sub class” an.
Die zweite Variante benutzt den statischen Objektkonstruktor von zcl_superclass, d. h. es entsteht entgegen Erwartung eines Benutzers der Klasse ein Objekt von zcl_superclass, nicht von zcl_subclass. Daher nimmt lv_string auch den per Konstruktor übergebenen Wert “Super class” an.

Bei ABAP ist dieses Verhalten besonders schwerwiegend, da statisch Methoden nicht überschrieben werden können, d. h. selbst, wenn man die Signatur von “get_instance” der Superklasse für die Instanziierung der Subklasse benutzen könnte, könnte man die Methode nicht überschreiben, um eine korrekte Instanz der Subklasse zu erzeugen.

Auch in Java werden statische Eigenschaften vererbt. Folgende Klassen implementieren das selbe Verhalten wie die oben dargestellten ABAP-Klassen. Der einzige Unterschied besteht darin, dass die Subklasse den statischen Konstruktor “getInstance()” überschreiben kann, sodass keine Methoden mit falschem Verhalten entstehen.

Java Klasse: SuperClass
public class SuperClass {
	String string;
	
	public static SuperClass getInstance() {
		return new SuperClass("Super class");
	}
	
	protected SuperClass(String string) {
		this.string = string;
	}
	
	public String toString() {
		return this.string;
	}
}
Java Klasse: SubClass
public class SubClass extends SuperClass {

	public static SubClass getInstance() {
		return new SubClass("Sub class");
	}
	
	protected SubClass(String string) {
		super(string);
	}
}

Bei der Verwenung statischer Objekt-Konstruktoren ist dennoch Vorsicht geboten. Zum einen ist es in vielen Szenarien sinnvoller, direkt eine Architektur mit Controller-Klassen zu erstellen, anstatt das gewünschte Verhalten statisch zu implementieren. Zum anderen gibt man mit statischen Objekt-Konstruktoren eine Konstruktor-Signatur vor, die – wenn, wie im Fall von Java, das Überschreiben statischer Methoden möglich ist – in der Subklasse nicht geändert werden kann, während ein “echter” Konstruktor lediglich von einer erbenden Klasse “bedient” werden muss.

Leave a Reply

Your email address will not be published. Required fields are marked *