Application Development and Automation Discussions
Join the discussions or start your own on all things application development, including tools and APIs, programming models, and keeping your skills sharp.
cancel
Showing results for 
Search instead for 
Did you mean: 
Read only

OO approach for dynpro developing

Former Member
0 Likes
656

Hi all!

Since my time as a java delveloper (not in the SAP environment) I am accustomed to object orientated gui development.

So, I try to find a way for object orientated dynpro programming. I found [the blog of Thomas Jung|https://www.sdn.sap.com/irj/scn/weblogs?blog=/pub/wlg/2322] [original link is broken] [original link is broken] [original link is broken];. Is this an official way for oo dynpro prgramming in SAP? It seems that only ALV is using this framwork.

Greetings,

Florian

Edited by: Florian Teepen on Feb 12, 2009 6:36 PM

4 REPLIES 4
Read only

naimesh_patel
Active Contributor
0 Likes
598

I don't know about the SAP Official way, but you can read this document for best practice:

[An Insider's Guide to Writing Robust, Understandable, Maintainable State of the Art ABAP Programs Part 1|https://www.sdn.sap.com/irj/scn/go/portal/prtroot/docs/library/uuid/c2992ca9-0e01-0010-adb1-b7629adb623c]

You can use the MVC design pattern (mix of OO ABAP + Classical).

Put your all business logic (model) in Classes

Use Function Groups as Controller to control the screens

Create Screens (view) in the Function Group.

Regards,

Naimesh Patel

Read only

0 Likes
598

Thanks for this document! I will study it. Perhaps it will help my in designing my applications!

Greetings,

Florian

Read only

0 Likes
598

Hi Florian.,

After developing module pool program via oo methodology, plz post ur code and steps here, so that many other developers including me will be benifitted .

Thanks and Regards.,

S.Sivakumar

Read only

0 Likes
598

Hi all!

I had time yesterday evening to read the document recommended by Naimesh. The following program is my first try. It would be great if somebody can give some helpful suggestions to enhance my approach.

It is a small report, that selects the first 25 user and displays some information on a simple dynpro. There are 2 buttons (next and previous user) to browse through the users.

D A T A S T R U C T U R E

First i create a dictionary structure (ZSTRUC_USER_DATA) for my dynpro.


BNAME type XUBNAME
PERSNUMBER type AD_PERSNUM
ADDRNUMBER type AD_ADDRNUM
NAME_FIRST type AD_NAMEFIR
NAME_LAST type AD_NAMELAS
SMTP_ADDR type AD_SMTPADR

M A I N C L A S S

Then I create the main class ZCL_START_DEMO. It contains a single method MAIN, that will be called by a transaction. This method creates the model, view and controller. It has no parameters.


**********************************************************************
* Method is called by transaction. It creates model, view and
* controller
**********************************************************************
METHOD main.

**********************************************************************
* L O C A L   O B J E C T S
**********************************************************************
  DATA lr_view       TYPE REF TO lcl_view.
  DATA lr_model      TYPE REF TO lcl_model.
  DATA lr_controller TYPE REF TO lcl_controller.

* Create model
  CREATE OBJECT lr_model.

* Create controller      
  CREATE OBJECT lr_controller
    EXPORTING
      ir_model = lr_model.

* Create view
  CREATE OBJECT lr_view 
    EXPORTING
      ir_model      = lr_model
      ir_controller = lr_controller.

* register view to model for notification about model changes
  lr_model->register_view( lr_view ).

* Display dynpro
  lr_view->display( ).

ENDMETHOD.

I N T E R F A C E S

So, the model contains the data that will be displayed by the view. The user interacts with the view, that notifies the controller about user actions. When the controller receives the user command, it makes changes to the model. When the model is changed, it notifies the registered views (in this case there is only one) for a refresh.

For the communcation between the different parts, I defined some interfaces. Interface LIF_MODEL_CHANGES will be implemented by the view to get notified when the model changed.

The model implements the interface LIF_MODEL_CHANGER to provide change-methods to the controller.

The controller implements the interface LIF_USER_COMMAND_LISTENER to listen for user commands. The view will send the command to the controller by using this interface.


**********************************************************************
* I N T E R F A C E S
**********************************************************************
* Interface for communication between model and view
* View listens for model changes
INTERFACE lif_model_listener.
  METHODS: fire_model_changed.
ENDINTERFACE.                    "lif_model_listener

* Interface for communication between model and controller
* Controller changes model
INTERFACE lif_model_changer.
  METHODS: next_user,
           previous_user.
ENDINTERFACE.                    "lif_model_changer

* Interface for communication between view and controller
* Controller receives the user command by the view
INTERFACE lif_user_command_listener.
  METHODS: fire_user_command IMPORTING id_command LIKE sy-ucomm.
ENDINTERFACE.                    "lif_user_command_listener

M O D E L

Now the model class. It is a really simple model. When creating a model object the data will be read from table USR21. After that, it notifies the views about changes by setting the next (in this case the first) user. It provides a structure of user data (type ZSTRUC_USER_DATA) for the view.

The methode NEXT_USER and PREVIOUS_USER are generally used by the controller. It reads the next (or the previous) user from the internal table (filled in constructor) and set a structure that will be used by the view. The methods notifies the view automatically about changes. The view can read the data from model that it is interessted in. For reading the model data the view uses the method GET_USER_DATA.

When a view is interessted in model changes, it is neccessary that it registered itself to the model by using the method REGISTER_VIEW. The model holds a internal table with references to all registered views. When the model changes (methods NEXT_USER and PREVIOUS_USER) the views a automatically notified from method NOTIFY_VIEWS. It called the method FIRE_MODEL_CHANGED whicht is defined in the interface LIF_MODEL_LISTENER (remind: this interface is implemented by any view that is interessted in model changes).


**********************************************************************
* The model holds the data. It will be changed by the controller and
* if it is changed, it notify the view by calling the method
* fire_model_changed
**********************************************************************
CLASS lcl_model DEFINITION.

  PUBLIC SECTION.
*   Interfaces
    INTERFACES lif_model_changer.
*   Methods
    METHODS: constructor,
             get_user_data RETURNING value(es_user_data) TYPE zstruc_user_data,
             register_view IMPORTING ir_view TYPE REF TO lif_model_listener.

  PRIVATE SECTION.
*   Data
    DATA md_index TYPE i.
*   Structures
    DATA ms_user_data TYPE zstruc_user_data.
*   Tables
    DATA mt_user_data TYPE STANDARD TABLE OF zstruc_user_data.
    DATA mt_view      TYPE STANDARD TABLE OF REF TO lif_model_listener.
*   Methods
    METHODS: notify_views.

ENDCLASS.                    "lcl_model DEFINITION


**********************************************************************
* The model provides the data for the view. It will be initialized in
* the constructor.
**********************************************************************
CLASS lcl_model IMPLEMENTATION.
* Class constructor
  METHOD constructor.
    FIELD-SYMBOLS <ls_user_data> LIKE LINE OF mt_user_data.

    SELECT * UP TO 25 ROWS
      FROM usr21
      INTO CORRESPONDING FIELDS OF TABLE mt_user_data
      WHERE persnumber <> ''
        AND addrnumber <> ''.

    LOOP AT mt_user_data ASSIGNING <ls_user_data>.
      SELECT SINGLE name_first name_last
        FROM adrp
        INTO (<ls_user_data>-name_first, <ls_user_data>-name_last)
       WHERE persnumber = <ls_user_data>-persnumber.

      SELECT SINGLE smtp_addr
        FROM adr6
        INTO <ls_user_data>-smtp_addr
       WHERE addrnumber = <ls_user_data>-addrnumber
         AND persnumber = <ls_user_data>-persnumber.
    ENDLOOP.

*   set data for first display
    me->lif_model_changer~next_user( ).
  ENDMETHOD.                    "constructor

* Set the next user in list
  METHOD lif_model_changer~next_user.
    md_index = md_index + 1.

    IF ( md_index > LINES( mt_user_data ) ).
      md_index = 1.
    ENDIF.

    READ TABLE mt_user_data INTO me->ms_user_data INDEX md_index.
    me->notify_views( ).
  ENDMETHOD.                    "lif_model_change~next_user

* Set the previous user in list
  METHOD lif_model_changer~previous_user.
    md_index = md_index - 1.

    IF ( md_index <= 0 ).
      md_index = LINES( mt_user_data ).
    ENDIF.

    READ TABLE mt_user_data INTO me->ms_user_data INDEX md_index.
    me->notify_views( ).
  ENDMETHOD.                    "lif_model_change~previous_user

* Delivers the user data
  METHOD get_user_data.
    es_user_data = me->ms_user_data.
  ENDMETHOD.                    "get_user_data

* Notify views about model changes
  METHOD notify_views.
    DATA ls_view LIKE LINE OF mt_view.

    LOOP AT mt_view INTO ls_view.
      ls_view->fire_model_changed( ).
    ENDLOOP.

  ENDMETHOD.                    "notify_views

* Method to register a view to listen for model changes
  METHOD register_view.
    IF ( ir_view IS NOT INITIAL ).
      APPEND ir_view TO mt_view.
    ENDIF.
  ENDMETHOD.                    "register_view

ENDCLASS.                    "lcl_model IMPLEMENTATION

V I E W

The view consists of multiple parts. The oo part will be represented by the local class LCL_VIEW. The serves as a wrapper class for fm calls. Method DISPLAY calls the dynpro and set the data for the first display. When the model changed, method FIRE_MODEL_CHANGED will be called. In this case the view requests the data from the model (the view has got a reference to the model). Method NOTIFY_VIEW is called by the dynpro. It send the user command to the controller.


**********************************************************************
* The view serves as wrapper class for the function modules.
**********************************************************************
CLASS lcl_view DEFINITION.

  PUBLIC SECTION.
*   Interfaces
    INTERFACES: lif_model_listener, zif_user_command.
*   Methods
    METHODS: constructor IMPORTING ir_model TYPE REF TO lcl_model
                                   ir_controller TYPE REF TO lif_user_command_listener,
             display.

  PRIVATE SECTION.
*   Objects
    DATA mr_model      TYPE REF TO lcl_model.
    DATA mr_controller TYPE REF TO lif_user_command_listener.

ENDCLASS.                    "lcl_view DEFINITION


**********************************************************************
* The view is a wrapper class for function modules.
**********************************************************************
CLASS lcl_view IMPLEMENTATION.

* Class constructor
  METHOD constructor.
    me->mr_model      = ir_model.
    me->mr_controller = ir_controller.
  ENDMETHOD.                    "constructor

* Method to display the dynpro
  METHOD display.
*   set data for first display
    me->lif_model_listener~fire_model_changed( ).

    CALL FUNCTION 'Z_FUNC_CALL_SCREEN'
      EXPORTING
        id_dynnr = '0100'
        ir_view  = me.
  ENDMETHOD.                    "display

**********************************************************************
* Method to notify the dynpro about model changes
**********************************************************************
  METHOD lif_model_listener~fire_model_changed.
    DATA ls_user_data TYPE zstruc_user_data.

    ls_user_data = me->mr_model->get_user_data( ).

    CALL FUNCTION 'Z_FUNC_SET_DATA'
      EXPORTING
        is_user_data = ls_user_data.

  ENDMETHOD.                    "lif_model_notify~fire_model_changed

* Receives user command from dynpro and push it to the controller
  METHOD zif_user_command~notify_view.
    me->mr_controller->fire_user_command( id_command ).
  ENDMETHOD.                    "zif_user_command~notify_view
ENDCLASS.                    "lcl_view IMPLEMENTATION

Since it is not possible to implement dynpros in a class pool, I create a function pool. I tried to minimize the number of global variables.


FUNCTION-POOL zfunc_user_data.              "MESSAGE-ID ..

**********************************************************************
* G L O B A L   D A T A
**********************************************************************
DATA gd_ok_code LIKE sy-ucomm.

**********************************************************************
* G L O B A L   S T R U C T U R E S
**********************************************************************
DATA gs_user_data TYPE zstruc_user_data.

**********************************************************************
* G L O B A L   O B J E C T S
**********************************************************************
DATA gr_view TYPE REF TO zif_user_command.

The dynpro will be controled by the class LCL_VIEW. This approach is used to obtain a complete object orientated concept in my design pattern. The function group contains the dynpro 0100. The process logic is quite simple. The module USER_COMMAND_0100 send the user command to the oo view. Thats all.


PROCESS BEFORE OUTPUT.
  MODULE status_0100.
*
PROCESS AFTER INPUT.
  MODULE user_command_0100.

**********************************************************************
* Set title and status
**********************************************************************
MODULE status_0100 OUTPUT.
  SET PF-STATUS 'STATUS100'.
  SET TITLEBAR 'TITLE100'.
ENDMODULE.                 " STATUS_0100  OUTPUT

**********************************************************************
* Process user command
**********************************************************************
MODULE user_command_0100 INPUT.
  gr_view->notify_view( gd_ok_code ).
ENDMODULE.                 " USER_COMMAND_0100  INPUT

There are two function modules available to control the dynpro. The first Z_FUNC_CALL_SCREEN is used to call the dynpro and to set the reference to the oo view.


FUNCTION z_func_call_screen .
*"----------------------------------------------------------------------
*"*"Lokale Schnittstelle:
*"  IMPORTING
*"     REFERENCE(ID_DYNNR) TYPE  SYDYNNR
*"     REFERENCE(IR_VIEW) TYPE REF TO  ZIF_USER_COMMAND
*"----------------------------------------------------------------------

  FREE gr_view.
  gr_view = ir_view.

  CALL SCREEN id_dynnr.

ENDFUNCTION.

The second Z_FUNC_SET_DATA is used to set the data in the dynpro.


FUNCTION z_func_set_data.
*"----------------------------------------------------------------------
*"*"Lokale Schnittstelle:
*"  IMPORTING
*"     REFERENCE(IS_USER_DATA) TYPE  ZSTRUC_USER_DATA
*"----------------------------------------------------------------------

  FREE gs_user_data.
  gs_user_data = is_user_data.

ENDFUNCTION.

Greetings,

Florian