Welche Redefinitionen gibt es?

In einem Projekt habe ich viel mit einer Superklasse und vielen Vererbungen gearbeitet. Die Superklasse besitzt sozusagen die Standardimplementierung für die einzelnen Funktionen und die Unterklassen können das Verhalten durch Redefinition ändern, wenn es erforderlich ist.

mit der Zeit sind viele Unterklassen zusammen gekommen. Das Konzept hat sich gut bewährt. Allerdings stellt sich nun das Problem, dass ich bei einer neuen Klasse nicht mehr wusste, bei welcher anderen Unterklasse es eine Abweichung zum Standard gibt. Um das herauszubekommen musste ich jede einzelne Klasse anklicken, die Methodenliste herunter scrollen, die entsprechende Methode finden und schauen ob und wie die Redefinition aussah.

Für einen Programmierer natürlich ein nicht zu tolerierendes Vorgehen! 8)

Finde Redefinitionen!

Der unten stehende Report nutzt die Klasse CL_OO_CLASS um die Subklassen zu ermitteln. In den Redefinition der Subklasse wird nach der vorgegebenen Methode gesucht. Ist diese vorhanden, also redefiniert, dann wird sie in der Liste ausgegeben.

Mit einem Doppelklick auf eine Methode wird der Quelltext im Docker angezeigt. Zur Anzeige des Quelltextes wird die Klasse CL_GUI_ABAPEDIT verwendet.

Coding

REPORT ztrcktrsr_find_redefinitions.

DATA gv_clsname         TYPE seoclsname.
DATA gv_cpdname         TYPE seocpdname.
DATA gt_dynp            TYPE TABLE OF dynpread WITH DEFAULT KEY. 

PARAMETERS p_clas TYPE seoclsname DEFAULT 'CL_GUI_CONTROL'.
PARAMETERS p_meth TYPE seocpdname DEFAULT 'FREE'.

AT SELECTION-SCREEN ON VALUE-REQUEST FOR p_clas.

  CALL FUNCTION 'SEOM_OO_PATTERN_SELECTION'
    IMPORTING
      clsname             gv_clsname
      cpdname             gv_cpdname
    EXCEPTIONS
      selection_cancelled 1
      OTHERS              2.
  IF sy-subrc 0.
    p_clas gv_clsname.
    gt_dynp VALUE #fieldname 'P_METH' fieldvalue gv_cpdname ).
    CALL FUNCTION 'DYNP_VALUES_UPDATE'
      EXPORTING
        dyname     sy-cprog
        dynumb     sy-dynnr
      TABLES
        dynpfields gt_dynp
      EXCEPTIONS
        OTHERS     8.
    IF sy-subrc <> 0.
      p_meth gv_cpdname.
    ENDIF.
  ENDIF. 
CLASS lcl_main DEFINITION.
  PUBLIC SECTION.
    METHODS on_double_click
                  FOR EVENT double_click OF cl_salv_events_table
      IMPORTING row column.
    METHODS docker.
    METHODS display.
    METHODS do
      IMPORTING
        i_class  TYPE clike
        i_method TYPE clike
        i_start  TYPE boolean_flg.
  PROTECTED SECTION.
    DATA mt_redef     TYPE STANDARD TABLE OF seoredef.
    DATA mo_docker    TYPE REF TO cl_gui_docking_container.
    DATA mo_editor    TYPE REF TO cl_gui_abapedit.
    METHODS display_source IMPORTING is_source TYPE seoredef.

ENDCLASS.

CLASS lcl_main IMPLEMENTATION.
  METHOD on_double_click.
    docker( ).
    DATA(redef) = mt_redef[ row ].

    display_source( redef ).

  ENDMETHOD.

  METHOD display_source.
    DATA lt_source TYPE STANDARD TABLE OF string.

    DATA(include) = cl_oo_classname_service=>get_method_include(
                      EXPORTING mtdkey = VALUE #( clsname = is_source-clsname
                                                  cpdname = is_source-mtdname ) ).
    READ REPORT include INTO lt_source.
    mo_editor->set_text( lt_source ).

  ENDMETHOD.

  METHOD docker.

    CHECK mo_docker IS INITIAL.
    mo_docker = NEW #( side = cl_gui_docking_container=>dock_at_right ratio = 50 ).
    mo_editor = NEW #( parent = mo_docker ).
    mo_editor->set_readonly_mode( 1 ).

  ENDMETHOD.

  METHOD display.

    TRY.
        " create SALV
        CALL METHOD cl_salv_table=>factory
          IMPORTING
            r_salv_table = DATA(lr_table)
          CHANGING
            t_table      = mt_redef.

        lr_table->get_functions( )->set_all( ).

        " register event DOUBLE_CLICK
        SET HANDLER on_double_click FOR lr_table->get_event( ).

        " hide columns which are not relevant
        DATA(lr_columns) = lr_table->get_columns( ).
        lr_columns->get_column( 'VERSION' )->set_technical( ).
        lr_columns->get_column( 'MTDABSTRCT' )->set_technical( ).
        lr_columns->get_column( 'MTDFINAL' )->set_technical( ).
        lr_columns->get_column( 'ATTVALUE' )->set_technical( ).
        lr_columns->get_column( 'EXPOSURE' )->set_technical( ).
        lr_table->display( ).
      CATCH cx_salv_error.
    ENDTRY.


  ENDMETHOD.


  METHOD do.

    DATA lr_class TYPE REF TO cl_oo_class.
    DATA lt_subclasses TYPE seo_relkeys.
    DATA ls_subclass   LIKE LINE OF lt_subclasses.

    TRY .
        lr_class ?= cl_oo_class=>get_instance( i_class ).

        LOOP AT lr_class->redefinitions INTO DATA(ls_redef) WHERE mtdname = i_method.
          APPEND ls_redef TO mt_redef.
        ENDLOOP.
        lt_subclasses = lr_class->get_subclasses( ).

        IF i_start = abap_true.
          " search
          LOOP AT lt_subclasses INTO ls_subclass.
            do( i_class  = ls_subclass-clsname
                i_method = i_method
                i_start  = space ).
          ENDLOOP.
        ENDIF.

      CATCH cx_class_not_existent.

    ENDTRY.

  ENDMETHOD.

ENDCLASS.


START-OF-SELECTION.

  DATA(main) = NEW lcl_main( ).
  main->do( i_class  = p_clas
            i_method = p_meth
            i_start  = abap_true ).
  main->display( ).

abapGit

Der inzwischen obligatorische Link zu Github: https://github.com/tricktresor/find_redefinitions

Enno Wulff