Design Patterns: a Singleton Class in SAP ABAP

The singleton is one of the best known software “design patterns” in object-oriented programming. It can also be implemented in ABAP.

Singleton means that only one single object of a class can exist. Creating a second instance of the class is technically impossible.

What do you need a singleton for?

The singleton is a a well-known excercise for object-oriented programming. You also need it for the ABAP certification. But you can find actual uses for this design pattern:

You can use it in object-oriented modelling, when it is important that you can only have one single instance of something, e.g. a log file, a special server, an application controller, a buffer, a cache of customizing data. In all these cases it might make sense to enforce the single instance technically.

Where does the English word “singleton” come from?

There is some computer vocabulary that non-native speakers of English only know in the context of computers. But many of these words use imagery and illustrative associations that might be interesting to know if English is not your mother language.

The word “singleton” is older than object oriented programming. You can find it (among other uses):

  • in card playing: if you only have one card of a suit
  • in mathematics: if you have a set that contains only one element
  • one single child in contrast to twins or triplets

core technical aspects of a singleton

In all object-oriented programming languages this is how a singleton works:

  • You make sure technically that only one object of the class can be instantiated. This means that the constructor is not publically accessible. Set its visibility to private.
  • The class has a public static method that returns the single instance. Usually it is called get_instance or getInstance (depending on the case recommendations of the language).
  • For generating this one and only instance you basically have two options:
    • eager initialization: create the singleton as early as possible
    • lazy initlialization: create the singleton as late as possible. That is the moment someone actually wants to access it for the first time.

Both is possible in ABAP and this is how to do it:

Lazy initialization

The most common approach is “lazy initialization”. You wait until you can no longer wait. Someone actually calls for the instance and it is your turn to answer.

So the method get_instance checks whether the object, the instance already exists. If so, it is simply returned. If not, it is created. A reference is stored for further calls. The reference is returned. Further calls then simply return the instance.

REPORT z_lazy_init_singleton.

" please note: create private !
CLASS lcl_lazy_init_singleton DEFINITION CREATE PRIVATE.

  PUBLIC SECTION.
    CLASS-METHODS: get_instance RETURNING value(r_instance) TYPE REF TO lcl_lazy_init_singleton.

    METHODS: do_something.
  PROTECTED SECTION.
  PRIVATE SECTION.
    " this is the one and only instance of the class
    CLASS-DATA: instance TYPE REF TO lcl_lazy_init_singleton.
ENDCLASS.

CLASS lcl_lazy_init_singleton IMPLEMENTATION.
  METHOD get_instance.
    " Lazy initialization:
    " first call creates the instance
    IF instance IS NOT BOUND.
      CREATE OBJECT instance.
    ENDIF.
    r_instance = instance.
  ENDMETHOD.

  METHOD do_something.
    WRITE : / 'doing something'.
  ENDMETHOD.
ENDCLASS.

START-OF-SELECTION.
  WRITE: / 'Lazy Initialization'.
  lcl_lazy_init_singleton=>get_instance( )->do_something( ).

Eager Initialization

Eager initialization means that you create the singleton as soon as the class is loaded. Then it is ready for use when it is needed for the first time. This can be an advantage or a disadvantage, depending on the circumstances.

It might be advantageous if the creation of the object takes a longer amount of time. So whenever the object is needed, even at first use, your reaction time is short.

It might however be disadvantageous if the singleton never gets used.

Technically ABAP at least offers a way to do eager initialization. Instead of creating the object at first access to get_instance you now use the static class-constructor. ABAP calls this special constructor method as soon as the class is loaded.

REPORT z_eager_init_singleton.

" please note: create private !
CLASS lcl_eager_init_singleton DEFINITION CREATE PRIVATE.

  PUBLIC SECTION.
    constants: some_constant type string value 'some_value'.

    CLASS-METHODS: get_instance RETURNING value(r_instance) TYPE REF TO lcl_eager_init_singleton.
    class-METHODS: class_constructor.
    METHODS: do_something.
  PROTECTED SECTION.
  PRIVATE SECTION.
    " the one and only instance of the class
    CLASS-DATA: instance TYPE REF TO lcl_eager_init_singleton.
ENDCLASS.

CLASS lcl_eager_init_singleton IMPLEMENTATION.

  method class_constructor.
     " eager initialization: create the object at first use of the class
     write : 'create object'.
     create object instance.
  ENDMETHOD.

  METHOD get_instance.
    r_instance = instance.
  ENDMETHOD.

  METHOD do_something.
    WRITE : / 'doing something'.
  ENDMETHOD.
ENDCLASS.

START-OF-SELECTION.
  WRITE: / 'Eager Initialization'.
  write: / 'accessing constant:', lcl_eager_init_singleton=>some_constant.
  WRITE: / 'accessing object'.

  lcl_eager_init_singleton=>get_instance( )->do_something( ).

Attention: the static class-constructor is different from the normal constructor of a class. The latter is not even defined (overwritten) here, as there is nothing for the constructor to do.

Here we are dealing with the static class constructor. It is called only once as soon as the class is loaded. For this it does not matter whether you call a method of the class or access an attribute of the class. It is enough just to load the class.

The output of the program is:

example of a singleton with eager initialization                                                                                       -----------------------------------------------------------
creating object
Eager Initialization
accessing constant: some_value
accessing object
doing something

This now is a bit surprising. The object is created earlier than I had thought. I had expected the object to be created at the use of the attribute. However this is a local class that only exists within the report. The call stack in the debugger shows that the class is loaded immediately after start-of-selection, before the first write command.

Eager initialization with a global class

This begs the question whether the cause is the local class or whether I misunderstood the class-constructor of ABAP. So let’s give it another try. Here is the new main program:

REPORT z_eager_init_singleton2.

start-of-selection.

  WRITE: / 'Eager Initialization'.
  write: / 'accessing constant:', zcl_eager_init_singleton=>some_constant.
  WRITE: / 'accessing object'.

  zcl_eager_init_singleton=>get_instance( )->do_something( ).

And here is the new singleton, this time using a global class (transaction SE24):

CLASS zcl_eager_init_singleton DEFINITION
  PUBLIC
  FINAL
  CREATE PRIVATE .

  PUBLIC SECTION.
    CONSTANTS: some_constant TYPE string VALUE 'some_value'.

    CLASS-METHODS: get_instance RETURNING value(r_instance) TYPE REF TO zcl_eager_init_singleton.
    CLASS-METHODS: class_constructor.
    METHODS: do_something.

  PROTECTED SECTION.
  PRIVATE SECTION.
*   the one and only instance
    CLASS-DATA: instance TYPE REF TO zcl_eager_init_singleton.

    METHODS constructor .
ENDCLASS.

CLASS ZCL_EAGER_INIT_SINGLETON IMPLEMENTATION.
  METHOD class_constructor.
*   eager initialization: create the object at first access of the class
    WRITE : 'creating object'.
    CREATE OBJECT instance.
  ENDMETHOD.

  METHOD constructor.
  ENDMETHOD.

  METHOD do_something.
    WRITE : / 'doing something'.
  ENDMETHOD.

  METHOD get_instance.
    r_instance = instance.
  ENDMETHOD.
ENDCLASS.

The result is the same:

example for a singleton with eager initialization                                                                                                 --------------------------------------------------
creating object
Eager Initialization
accessing constant: some_value
accessing instance
doing something

Also here it is sufficient to use the class in the program to call the class-constructor. Automatically as first action within start-of-selection, before any other command is executed. The behaviour is the same as with a local class.

By the way: limiting a constructor to private is possible in ABAP, even in the class editor SE24. In earlier versions of ABAP this was not the case. And limiting the constructor to private is exactly what we need for the singleton pattern.

This article is also available in German.Opens in a new tab.

Recommended reading

You can find more articles about SAP here.

Image: thanks a lot to DevanathOpens in a new tab. on PixabayOpens in a new tab.

Recent Posts