genericsinheritancedesign-patternsabapabstraction

Design pattern to return an internal table of various types


The documentation states: return parameters of functional methods have to be fully typed.

I'm trying to dance around that prerequisite in the following case:

I have a program where the user picks an object on screen 1000 and can make various changes to it on screen 2000. The objects that the user can pick are of varied types. The object is presented on screen 2000 in an ALV, where the columns depend on the object's type. The program handles the user actions in mostly the same way no matter the object type.

The way the program is laid out is: an abstract class defines the default behaviour for all object types, then a child-class for each object type redefines methods where needed.

The class handling the object's data has the method get_data_ref(). This method returns a reference to a private internal table from the subclass, that contains an object's data. This internal table is declared in each subclass with a different row type.

An abstract method get_fieldcatalog() returns the fieldcatalog for the given object type. This method is redefined in each of the subclasses.

To display the ALV, I get the table reference from get_data_ref(), assign a field symbol to it and pass the field symbol to the ALV using method SET_TABLE_FOR_FIRST_DISPLAY() along with the fieldcatalog.

It works. But it is wrong.

  • It gives direct access to a private attribute of my class by referencing it. The private internal table can be altered from outside of the class, which is against the abstraction principle.
  • Is it safe ? Could the internal table be freed from memory while a pointer to it still existed ?

Is there a better way to do this ?


Solution

  • I solved this by using a generic EXPORTING parameter instead of a RETURNING one in the get_data() method (as suggested by Sandra Rossi) and returning a RTTS object through a separate GET_TABLEDESCR( ) method. In the calling class the internal table is typed at runtime using the descriptor object.

    In the calling class:

    DATA(lo_tabledescr) = go_data->GET_TABLEDESCR( ).
    CREATE DATA lr_dref TYPE HANDLE lo_tabledescr.
    
    ASSIGN lr_dref->* TO <lt_table>.
    CHECK <lt_table> IS ASSIGNED.
    go_data->GET_DATA( changing ct_data = <lt_table> ).
    

    In the class of go_data:

    METHOD GET_TABLEDESCR. " This method returns ro_descr TYPE REF TO cl_abap_tabledescr
      DATA lo_structdescr TYPE REF TO cl_abap_structdescr.
      lo_structdescr ?= CL_ABAP_STRUCTDESCR=>DESCRIBE_BY_NAME( P_NAME = 'your_linetype_name' ).
    
      ro_descr = cl_abap_tabledescr=>GET(
        exporting
          P_LINE_TYPE  = lo_structdescr      " Row Type
      ).
    ENDMETHOD.