[ABAP] OO: Vererbung, Methodenredefinition, Vererbungshierarchie

* Einfache Klasse für Demo von Vererbung von Oberklasse an Unterklasse
* Methodenredefinition, Vererbungshierarchie

* Oberklasse
CLASS lcl_auto DEFINITION.
  PUBLIC SECTION.
* Instanzkonstruktor
    METHODS:
      constructor
        IMPORTING
          i_name TYPE string.

* funktionale Instanzmethode, gibt Namen zurück
    METHODS:
      get_name
        RETURNING VALUE(rv_name) TYPE string.

* funktionale Instanzmethode, gibt Ergebnis zurück
    METHODS:
      get_type_and_name
        RETURNING VALUE(rv_type_name) TYPE string.

  PROTECTED SECTION.
* funktionale Instanzmethode, ist nur innerhalb der Vererbungshierarchie sichtbar
    METHODS:
      get_type
        RETURNING VALUE(rv_type) TYPE string.

  PRIVATE SECTION.
    DATA: gv_name TYPE string.
ENDCLASS.

CLASS lcl_auto IMPLEMENTATION.
  METHOD constructor.
    gv_name = i_name.
  ENDMETHOD.

  METHOD get_name.
    rv_name = gv_name.
  ENDMETHOD.

  METHOD get_type_and_name.
* Aufruf der verdeckten Klassen-Funktion über me-> (kann auch weggelassen werden)
    rv_type_name = |{ me->get_type( ) }: { gv_name }|.
  ENDMETHOD.

  METHOD get_type.
    rv_type = 'AUTO'.
  ENDMETHOD.
ENDCLASS.

* Unterklasse lcl_kombi, erbt von lcl_auto
CLASS lcl_kombi DEFINITION INHERITING FROM lcl_auto.
  PROTECTED SECTION.
* Methode der Oberklasse wird überschrieben
    METHODS:
      get_type REDEFINITION.
ENDCLASS.

CLASS lcl_kombi IMPLEMENTATION.
  METHOD get_type.
* Aufruf der Funktion der Oberklasse über "super"
    rv_type = |{ super->get_type( ) } -> KOMBI|.
  ENDMETHOD.
ENDCLASS.

START-OF-SELECTION.
* Kombi erzeugen
  DATA(o_kombi) = NEW lcl_kombi( 'Audi A3' ).
* Methode der Klasse lcl_auto auftrufen
  WRITE: / o_kombi->get_name( ).
* Methode der Klasse lcl_kombi auftrufen
  WRITE: / o_kombi->get_type_and_name( ).

[ABAP] OO: Implementation einer Factory-Klasse, Methodenverkettung (Method-Chaining)

* Einfache Klasse für Demo einer Factory-Klasse

* ist nicht über den Kontruktor von außen instanziierbar (CREATE PRIVATE), kann nur sich selbst instanziieren
* von lcl_factorydemo kann nicht geerbt werden (FINAL)
CLASS lcl_factorydemo DEFINITION FINAL CREATE PRIVATE.
  PUBLIC SECTION.
* statische Factory-Methode, übernimmt die Funktion des Konstruktors mit einigen organisatorischen Verbesserungen
    CLASS-METHODS:
      factory
        IMPORTING
                  i_object_name      TYPE string
        RETURNING VALUE(ro_instance) TYPE REF TO lcl_factorydemo.

* statische Methode, zeigt die interne sortierte Objektliste
    CLASS-METHODS:
      get_object_list.

* Instanzmethode, gibt Objektnamen
    METHODS:
      get_name
        RETURNING VALUE(rv_object_name) TYPE string.

  PRIVATE SECTION.
* eigener Listtyp zur Verwaltung der internen Objektreferenzen
* über "name" können die Objektreferenzen gesucht werden
    TYPES: BEGIN OF ty_instances,
             name       TYPE        string,
             o_instance TYPE REF TO lcl_factorydemo,
           END OF ty_instances.

* sortierte Liste zur Verwaltung der Objektreferenzen, Primärschlüssel ist "name"
    CLASS-DATA: git_instances TYPE SORTED TABLE OF ty_instances WITH UNIQUE KEY name.

* Instanzvariable, speichert Objektnamen
    DATA: gv_object_name TYPE string.

* versteckter Instanzkonstruktor, ist von außerhalb der Klasse nicht aufrufbar (CREATE PRIVATE)
    METHODS:
      constructor
        IMPORTING
          i_object_name TYPE string.
ENDCLASS.

CLASS lcl_factorydemo IMPLEMENTATION.
* versteckter Instanzkonstruktor, ist von außerhalb der Klasse nicht aufrufbar (CREATE PRIVATE)
  METHOD constructor.
    gv_object_name = i_object_name.
  ENDMETHOD.

* statische Factory-Methode
  METHOD factory.
    TRY.
* Instanz über den Namen suchen, wenn nicht vorhanden wird eine Exception CX_SY_ITAB_LINE_NOT_FOUND geworfen
        ro_instance = git_instances[ name = i_object_name ]-o_instance.
      CATCH cx_sy_itab_line_not_found.
* wenn also das Objekt nicht vorhanden ist, dann neues erzeugen
        ro_instance = NEW #( i_object_name ).
* und in die iTab eintragen, wird automatisch anhand des Namens einsortiert
        INSERT VALUE #( name = i_object_name
                        o_instance = ro_instance ) INTO TABLE git_instances.
    ENDTRY.
  ENDMETHOD.
* Instanzmethode, gibt Objektnamen
  METHOD get_name.
    rv_object_name = gv_object_name.
  ENDMETHOD.
* statische Methode, zeigt die interne sortierte Objektliste
  METHOD get_object_list.
    LOOP AT git_instances ASSIGNING FIELD-SYMBOL(<fs_inst>).
      WRITE: / <fs_inst>-name.
    ENDLOOP.
  ENDMETHOD.
ENDCLASS.

START-OF-SELECTION.
* Drei Objekte per Factory-Methode erzeugen
* die ersten zwei Objekte werden erzeugt, da die Namen noch nicht
* in der internen Liste vorhanden sind
* die Objekte werden automatisch nach Namen sortiert (SORTED TABLE)
  DATA(o_ref1) = lcl_factorydemo=>factory( i_object_name = 'OBJ_2' ).
  WRITE: / o_ref1->get_name( ).

* Beispiel für Methodenverkettung (Method-Chaining)
  WRITE: / lcl_factorydemo=>factory( i_object_name = 'OBJ_1' )->get_name( ).

* das dritte Objekt wird nicht erzeugt, da schon ein Objekt mit dem gleichen Namen existiert
* daher wird nur die Referenz auf das namensgleiche Objekt zurückgegeben
  DATA(o_ref3) = lcl_factorydemo=>factory( i_object_name = 'OBJ_1' ).
  WRITE: / o_ref3->get_name( ).

  ULINE.

* sortierte Objektliste ausgeben -> nur zwei Objekte
* mit unterschiedlichen Namen werden angezeigt
  lcl_factorydemo=>get_object_list( ).

[ABAP] OO: Interfacedefinition, Generalisierung, Spezialisierung

* Einfache Klassen für Demo für Verwendung von Interfaces
* Über Interfaces kann im ABAP Mehrfachvererbung (Polymorphie) realisiert werden

* Interface, dient als Schablone, ohne Implementierungen
INTERFACE lif_auto.
  METHODS:
* Interface-Methode, liefert Fahrtrichtung
    get_direction
      RETURNING VALUE(rv_direction) TYPE string.
ENDINTERFACE.

* Klasse Kombi, spezialisert das Interface lif_auto
CLASS lcl_kombi DEFINITION.
  PUBLIC SECTION.
* Implementiert das Interface lif_auto
    INTERFACES:
      lif_auto.

* ALias-Namen als Vereinfachung für Zugriff definieren
    ALIASES:
      get_direction FOR lif_auto~get_direction.

    METHODS:
      get_name
        RETURNING VALUE(rv_name) TYPE string.
ENDCLASS.

CLASS lcl_kombi IMPLEMENTATION.
* Implementierung der Interface-Methode, liefert Fahrtrichtung
  METHOD lif_auto~get_direction.
    rv_direction = 'Berlin'.
  ENDMETHOD.
* Instanzmethode, liefert Namen
  METHOD get_name.
    rv_name = 'Opel'.
  ENDMETHOD.
ENDCLASS.

START-OF-SELECTION.
* Objekt der Klasse Kombi + Funktionsaufruf
  DATA(o_ref) = NEW lcl_kombi( ).
* Aufruf der Instanzmethode
  WRITE: / 'Name:', o_ref->get_name( ).
* Aufruf der Interfacemethode allgemein
  WRITE: / 'Direction:', o_ref->lif_auto~get_direction( ).
* Aufruf der Interfacemethode über Alias-Namen (ALIASES)
  WRITE: / 'Direction:', o_ref->get_direction( ).

[ABAP] OO: Statischer Konstruktor, Instanzkonstruktor, statischer und dynamischer Methodenaufruf

* Einfache Klasse für Demo des statischen Konstruktors und des Instanzkonstruktors
* sowie eines statischen und dynamischen Methodenaufrufs
CLASS lcl_demo DEFINITION.
  PUBLIC SECTION.
* Instanzkonstruktor
    METHODS:
      constructor.

* funktionale Instanzmethode, gibt Ergebnis zurück
    METHODS:
      add
        IMPORTING
                  i_var1        TYPE i
                  i_var2        TYPE i
        RETURNING VALUE(rv_erg) TYPE i.

    CLASS-METHODS:
* statischer Konstruktor
      class_constructor.

* statische funktionale Methode, gibt Ergebnis zurück
    CLASS-METHODS:
      mul
        IMPORTING
                  i_var1        TYPE i
                  i_var2        TYPE i
        RETURNING VALUE(rv_erg) TYPE i.
ENDCLASS.

CLASS lcl_demo IMPLEMENTATION.
  METHOD class_constructor.
    WRITE: / 'statischer Konstruktor'.
  ENDMETHOD.

  METHOD constructor.
    WRITE: / 'dynamischer Konstruktor'.
  ENDMETHOD.

  METHOD add.
    rv_erg = i_var1 + i_var2.
  ENDMETHOD.

  METHOD mul.
    rv_erg = i_var1 * i_var2.
  ENDMETHOD.
ENDCLASS.

START-OF-SELECTION.

* erster Aufruf einer Methode der Klasse lcl_demo durch den Aufruf von mul( )
* -> ruft den Klassenkonstruktor, danach erst wird mul( ) statisch prozessiert
  WRITE: / lcl_demo=>mul( i_var1 = 4 i_var2 = 3 ).

* Objekt der Klasse lcl_demo erzeugen
  DATA(o_ref) = NEW lcl_demo( ).
* Methode add( ) aurufen
  WRITE: / o_ref->add( i_var1 = 2 i_var2 = 3 ).
* Methode mul( ) dynamisch prozessieren
  WRITE: / o_ref->mul( i_var1 = 2 i_var2 = 3 ).

[ABAP] OO: Instanzkonstruktor, funktionale Instanzmethode, Exceptionhandling

* Einfache Klasse für Demo des Konstruktors, Instanzmethode, Exceptionhandling
CLASS lcl_demo DEFINITION.
  PUBLIC SECTION.
* Instanzkonstruktor mit Übergabeparameter
* Propagiert Exception vom Typ cx_sy_create_object_error
    METHODS:
      constructor
        IMPORTING
          i_name TYPE string
        RAISING
          cx_sy_create_object_error.

* funktionale Instanzmethode, gibt Namen zurück
    METHODS:
      get_name RETURNING VALUE(rv_name) TYPE string.

  PRIVATE SECTION.
* globale, private Variable zur Speicherung des Namens
    DATA: gv_name TYPE string.
ENDCLASS.

CLASS lcl_demo IMPLEMENTATION.
  METHOD constructor.
* prüfen, ob Name leer
    IF i_name = ''.
* Exception werfen
      RAISE EXCEPTION TYPE cx_sy_create_object_error.
    ELSE.
      gv_name = i_name.
    ENDIF.
  ENDMETHOD.

  METHOD get_name.
* Namen zurückgeben
    rv_name = gv_name.
  ENDMETHOD.
ENDCLASS.

START-OF-SELECTION.
* Exception provozieren
  TRY.
      DATA(o_ref) = NEW lcl_demo( i_name = '' ).

      WRITE: / o_ref->get_name( ).

    CATCH cx_sy_create_object_error INTO DATA(e_txt).
      WRITE: / e_txt->get_text( ).
  ENDTRY.
  
* "normale" Abarbeitung
  TRY.
      DATA(o_ref) = NEW lcl_demo( i_name = 'Test' ).

      WRITE: / o_ref->get_name( ).

    CATCH cx_sy_create_object_error INTO DATA(e_txt).
      WRITE: / e_txt->get_text( ).
  ENDTRY.

[ABAP] OO: Implementation einer Singleton-Klasse

* Singleton-Klasse, kann durch den Zusatz CREATE PRIVATE nur sich selbst instanziieren
* stellt einen Spezialfall einer Factory-Klasse dar
CLASS lcl_singleton DEFINITION CREATE PRIVATE.
  PUBLIC SECTION.
* Statischer Konstruktor, wird nur einmal aufgerufen
* erzeugt genau eine Referenz auf Singleton-Objekt
    CLASS-METHODS:
      class_constructor.

* Factory-Methode -> Gibt immer die gleiche Referenz auf Singleton-Objekt zurück
    CLASS-METHODS:
      get_instance RETURNING VALUE(ret_singleton) TYPE REF TO lcl_singleton.

* Testmethode, gibt eine GUID zurück
    METHODS:
      get_guid RETURNING VALUE(ret_guid) TYPE sysuuid_c32.

  PRIVATE SECTION.
* Referenz auf Singleton-Objekt
    CLASS-DATA: o_singleton TYPE REF TO lcl_singleton.
ENDCLASS.

CLASS lcl_singleton IMPLEMENTATION.
* Statischer Konstruktor, wird nur einmal aufgerufen
* erzeugt genau eine Referenz auf Singleton-Objekt
  METHOD class_constructor.
    o_singleton = NEW #( ).
  ENDMETHOD.

* Factory-Methode -> Gibt immer die gleiche Referenz auf Singleton-Objekt zurück
  METHOD get_instance.
    ret_singleton = o_singleton.
  ENDMETHOD.

* Testmethode, gibt eine GUID zurück
  METHOD get_guid.
    TRY.
        ret_guid = cl_system_uuid=>create_uuid_c32_static( ).
      CATCH cx_root.
    ENDTRY.
  ENDMETHOD.
ENDCLASS.

START-OF-SELECTION.
  DATA(o_ref) = lcl_singleton=>get_instance( ).

  WRITE: / |{ o_ref->get_guid( ) }|.

[ABAP] OO: Inline-Deklarationen, interne Tabelle als Referenz

* Typ-Deklarationen
* Objekt Person
TYPES: BEGIN OF ty_person,
         name TYPE string,
         age  TYPE i,
       END OF ty_person.

* Tabelle mit Personen
TYPES: ty_it_person TYPE STANDARD TABLE OF ty_person WITH DEFAULT KEY.

* Objekt-Referenz auf interne Tabelle mit Vorbelegung
DATA(it_ref) = NEW ty_it_person( ( age = 10 name = 'Udo' )
                                 ( age = 20 name = 'Horst' )
                                 ( age = 30 name = 'Ulf' ) ).

* Objekt-Referenz auf Feldsymbol
ASSIGN it_ref->* TO FIELD-SYMBOL(<fs_it_person>).

* Datenausgabe
cl_demo_output=>display( <fs_it_person> ).

* Tabelle leeren
FREE: <fs_it_person>.
* Referenz löschen
FREE: it_ref.

[ABAP] Beispiel für Implementation einer lokalen Klasse

CLASS cl_one DEFINITION.
* Public-Deklarationen, global inner- und außerhalb des Objektes sichtbar
  PUBLIC SECTION.
    DATA: pu_val3 TYPE i.        " dyn. Variable, nur zur Obj-Laufzeit verfügbar

    CLASS-DATA: txt TYPE string. " statische Public-Variable
    CLASS-DATA: int TYPE i.      " statische Public-Variable

* statische Methode, hat keinen Zugriff auf pu_val3
    CLASS-METHODS: function_one
      IMPORTING
                i_txt          TYPE string
      RETURNING VALUE(ret_val) TYPE string. " wenn RETURNING VALUE, dann kein EXPORTING oder CHANGING möglich

* statische Methode, hat keinen Zugriff auf pu_val3
    CLASS-METHODS: function_two
      IMPORTING
                i_txt          TYPE string
                i_val          TYPE i
      RETURNING VALUE(ret_val) TYPE string. " wenn RETURNING VALUE, dann kein EXPORTING oder CHANGING möglich

* dynamische Methode, hat Zugriff auf pu_val3
    METHODS: function_three
      IMPORTING
                i_val1         TYPE i DEFAULT 10 " Default-Wert, falls Parameter nicht gesetzt
                i_val2         TYPE i DEFAULT 20 " Default-Wert, falls Parameter nicht gesetzt
      RETURNING VALUE(ret_val) TYPE i.           " wenn RETURNING VALUE, dann kein EXPORTING oder CHANGING möglich

* dynamische Methode, einfaches Exceptionhandling
    METHODS: function_four
      IMPORTING
                i_val1         TYPE i
      RETURNING VALUE(ret_val) TYPE i
      RAISING   cx_sy_arithmetic_error.

    METHODS: constructor.
* Private-Deklarationen, nur innerhalb der Klasse sichtbar
  PRIVATE SECTION.
    DATA: pr_val3 TYPE i.
ENDCLASS.

CLASS cl_one IMPLEMENTATION.
* Constructor der Klasse
  METHOD constructor.
    me->pr_val3 = 100.
  ENDMETHOD.
* Funktion mit einem Übergabeparameter
  method function_one.
    DATA: s TYPE string VALUE 'Return: '.
    ret_val = |{ s } { i_txt }|.
  ENDMETHOD.

* Funktion mit zwei Übergabeparametern
  METHOD function_two.
    ret_val = |{ i_txt } { i_val }|.
  ENDMETHOD.

* Funktion mit zwei Übergabeparametern und DEFAULT-Werten
* Verwendung des me-> Operators für den Zugriff auf Attribute der Klasse
  METHOD function_three.
    ret_val = ( me->pu_val3 + me->pr_val3 ) * ( i_val1 + i_val2 ).
  ENDMETHOD.

* Funktion mit einem Übergabeparameter
* löst bei DIV0 -> cx_sy_arithmetic_error aus
  METHOD function_four.
    ret_val = 100 / i_val1.
  ENDMETHOD.
ENDCLASS.

INITIALIZATION.
  cl_one=>int = 1.
  cl_one=>txt = |Test.|.

START-OF-SELECTION.
* statische Objektaufrufe
  WRITE: / cl_one=>int.
  WRITE: / cl_one=>txt.

  WRITE: / cl_one=>function_one( |Input.| ).

  WRITE: / cl_one=>function_two( i_txt = |Input2:|
                                 i_val = 1 ).

* dynamische Objektaufrufe
  DATA(o_cl_one) = NEW cl_one( ).
  o_cl_one->pu_val3 = 10.
  WRITE: / o_cl_one->function_three( ).
  WRITE: / o_cl_one->function_three( i_val1 = 1
                                     i_val2 = 2 ).

* Exception abfangen
  TRY.
      WRITE: / o_cl_one->function_four( 0 ). " Division durch 0 auslösen
    CATCH cx_root INTO DATA(e_text).
      WRITE: / e_text->get_text( ).
  ENDTRY.

[ABAP] ADBC – ABAP Database Connectivity

* ab V6.10 verfügbar
* http://zevolving.com/2013/05/abap-database-connectivity-adbc/
* https://archive.sap.com/discussions/thread/447887

* DEMO_ADBC_DDL_DML
* DEMO_ADBC_DDL_DML_BINDING
* DEMO_ADBC_DDL_DML_BULK_ACCESS
* DEMO_ADBC_PREPARED_STATEMENT
* DEMO_ADBC_QUERY
* DEMO_ADBC_STORED_PROCEDURE

DATA: o_salv TYPE REF TO cl_salv_table.        " Anzeigeobjekt SALV Grid
DATA: it_cols TYPE adbc_column_tab.            " Selektierte Spalten
DATA: it_tsp01 TYPE STANDARD TABLE OF tsp01.   " Ausgabetabelle
DATA: par TYPE i VALUE 2000.                   " Parameter für Selektion

START-OF-SELECTION.

* zu verarbeitende Spalten
  it_cols = VALUE #( ( 'RQIDENT' )
                     ( 'RQDEST' )
                     ( 'RQPAPER' )
                     ( 'RQO1NAME' ) ).

* Spaltennnamen durch Komma trennen
  DATA(cols) = to_lower( concat_lines_of( table = it_cols sep = ',' ) ).
* Spaltennamen und Parameter in SQL einfügen
  DATA(lv_query) = |SELECT { cols } FROM tsp01 WHERE rqident > '{ par }'|.

  TRY.
* SQL-Connection öffnen
      DATA(o_sql_connection) = NEW cl_sql_connection( ).

      IF abap_true <> o_sql_connection->is_closed( ).
* SQL-Statement erzeugen
        DATA(o_sql) = NEW cl_sql_statement( con_ref = o_sql_connection ).
* Query ausführen
        DATA(o_result) = o_sql->execute_query( lv_query ).
* Ergebnismenge soll in interne Tabelle it_tsp01 und nur die Spalten, welche in it_cols stehen
        o_result->set_param_table( itab_ref             = REF #( it_tsp01 )
                                   corresponding_fields = it_cols ).
* Ergebnismenge in interne Tabelle lesen
* cnt enthält die Anzahl der gelesenen Datensätze
        DATA(cnt) = o_result->next_package( ).
* Ergebnismenge schließen
        o_result->close( ).
* SQL-Connection schließen
        o_sql_connection->close( ).

        IF cnt > 0.
          cl_salv_table=>factory( IMPORTING
                                    r_salv_table = o_salv
                                  CHANGING
                                    t_table = it_tsp01 ).

          o_salv->get_display_settings( )->set_list_header( |DBMS: { o_sql_connection->get_dbms( ) }| ).
          o_salv->get_functions( )->set_all( abap_true ).
          o_salv->get_display_settings( )->set_striped_pattern( abap_true ).
          o_salv->display( ).
        ENDIF.
      ENDIF.
    CATCH cx_root INTO DATA(e_text).
      WRITE: / e_text->get_text( ).
  ENDTRY.

[ABAP] Interne Tabelle mit NEW-Operator erstellen / Zugriff über Feldsymbole und Table Expressions

* Zeile
TYPES: BEGIN OF ty_data,
         kunnr TYPE i,
         name TYPE string,
         ort TYPE string,
       END   OF ty_data.
* Tabellentyp
TYPES: it_itab TYPE STANDARD TABLE OF ty_data WITH DEFAULT KEY.
* Feldsymbol für Zugriff
FIELD-SYMBOLS: <lt_text> TYPE it_itab.

* neue interne Tabelle mit Inhalt erstellen
DATA(dref) = NEW it_itab( ( kunnr = '123' name = 'ABCD' ort = 'LV' )
                          ( kunnr = '456' name = 'XYZ'  ort = 'LA' ) ).

* Zuweisung Feldsymbol
ASSIGN dref->* TO <lt_text>.

* Zugriff auf Inhalt der internen Tabelle über Feldsymbol und Table Expression
WRITE: / <lt_text>[ 1 ]-ort.