Additional Blogs by Members
cancel
Showing results for 
Search instead for 
Did you mean: 
former_member215870
Participant

Keyword

Screen programming with ABAP OO, singleton pattern, Adapter pattern, polymorphism via interfaces.

 

The scenario

A company that has branches in different countries wants to implement a Dialog Application common for all these branches. The Screen should display the working hours for a specific country and an ALV grid should display some data.

The application takes as an input the company code by the user. Then instantiate the business object. The business class also instantiate 2 locals classes, which implement both of them the same interface. Based on the company code the business class could decide from which class will receive the localized data (each country have different laws and procedures). For this purpose I am using inside the class the technique “Polymorphism via interface”. 

For simplistic reason I have remove the complexity from the business process and I have pay special attention to the control concepts.

 

Implementation Strategy

 

Following the OO concepts and the “Singleton” and the "adapter" patterns we should:

  • Separate the Business Logic from the Programs’ Flow Logic.
  • All the “functions” of the application should be wrapping into classes.
  • A business object that represents the application should be able to instantiate only once and not 2 times.
  • Screen flow logic should be controlled by methods
  • When the localize classes (the classes that describe the business process of each country) are instantiating, then an event should be raised. That event should be handled by the main class, so later to be able to know with witch class should interact.

 

The application makes use of the following classes and interfaces.

 

Class / Interface Name

function

Type

Lcl_app

Model class  - Wrap all the business function

Class (create private)

Lcl_local_gr

Localize class for Greece. Perform all the business calculations

Class – implement  “if_localazation”  interface

Lcl_local_ch

Localize class for Switzerland. Perform all the business calculations

Class – implement  “if_localazation”  interface

if_localazation

Common methods name and variable

interface

 

  1. We are bringing into life the model/application class
  2. We are creating the screen objects (container, alv grid, fieldcatalogs, etc)
  3. We are creating the local business classes, that hold the business processes per country
  4. When a business class is created we are raising an interface event and the handler method is appending the instance into a table of instances.

 

Screen - Flow Logic

Screen 100 – Flow Logic

process before output.
  module pbo.
*
process after input.
  module exit_command at exit-command.
  module pai.

 

Application Code

The main program

*&---------------------------------------------------------------------*
*& Report  ZBC_GMICH_04
*&
*&---------------------------------------------------------------------*
*&
*&
*&---------------------------------------------------------------------*

report  zbc_gmich_04.

include zbc_gmich_04_data.
include zbc_gmich_04_class.
include zbc_gmich_04_modules.
*include zbc_gmich_04_utest.


parameters: p_bukrs like t001-bukrs obligatory.

start-of-selection.

lcl_app=>run_application( iv_bukrs = p_bukrs ).

 

Global data

*&---------------------------------------------------------------------*
*&  Include           ZBC_GMICH_04_DATA
*&---------------------------------------------------------------------*


tables: rlmob, t001.

data: begin of scr_100,
         bukrs type bukrs,
         work_days type i,
      end of scr_100.

 

Classes – Definition & implementation

*&---------------------------------------------------------------------*
*&  Include           ZBC_GMICH_04_CLASS
*&---------------------------------------------------------------------*
data: ok_code like sy-ucomm.


class: lcl_local_gr definition deferred,
       lcl_local_ch definition deferred.
*----------------------------------------------------------------------*
*       INTERFACE if_localazation
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
interface if_localazation.
  methods: init,
           calc_working_days returning value(ev_days) type i,
           get_alv_data exporting et_ltak type tt_ltak.

  class-data: gt_ref type standard table of ref to if_localazation.
  events: obj_created exporting value(ev_bukrs) type bukrs.
  data: bukrs type bukrs.
endinterface.                    "if_localazation


*----------------------------------------------------------------------*
*       CLASS LCL_APP DEFINITION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
class lcl_app definition create private.
  public section.
    methods: constructor importing value(iv_bukrs) type bukrs.


    class-methods: class_constructor,
                   run_application importing iv_bukrs type bukrs,
                   pbo,

                   pai importing iv_code type sy-ucomm,
                   exit_command importing iv_code type sy-ucomm.

  private section.
    methods:
             set_status importing iv_status type string,
             reg_local_obj for event obj_created of if_localazation importing ev_bukrs sender,
             get_alv_data,
             set_alv_data,
             leave_screen.

    class-methods: build_fieldcatalog,
                   build_screen_object.

    data: ref_local_gr type ref to lcl_local_gr,
          ref_local_ch type ref to lcl_local_ch.

    class-data: bukrs type bukrs,
                screen_status type string,
                ok_code type sy-ucomm,
                fieldcat type lvc_t_fcat,
                gt_alv_data type standard table of ltak,
                gt_ref type standard table of ref to if_localazation.

    class-data: ref_app type ref to lcl_app,
                ref_container type ref to cl_gui_custom_container,
                ref_alv type ref to cl_gui_alv_grid.


endclass.                    "LCL_APP DEFINITION


*----------------------------------------------------------------------*
*       CLASS lcl_local_gr DEFINITION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
class lcl_local_gr definition.
  public section.
    interfaces: if_localazation.
    methods: constructor.

endclass.                    "lcl_local_gr DEFINITION

*----------------------------------------------------------------------*
*       CLASS lcl_local_ch DEFINITION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
class lcl_local_ch definition.
  public section.
    interfaces: if_localazation.
    methods: constructor.
endclass.                    "lcl_local_ch DEFINITION

*----------------------------------------------------------------------*
*       CLASS LCL_APP IMPLEMENTATION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
class lcl_app implementation.
  method class_constructor.
    call method build_fieldcatalog.
    call method build_screen_object.
  endmethod.

  method build_screen_object.
    create object ref_container
      exporting
*        PARENT                      =
        container_name              = 'CUSTOM'
*        STYLE                       =
*        LIFETIME                    = lifetime_default
*        REPID                       =
*        DYNNR                       =
*        NO_AUTODEF_PROGID_DYNNR     =
      exceptions
        cntl_error                  = 1
        cntl_system_error           = 2
        create_error                = 3
        lifetime_error              = 4
        lifetime_dynpro_dynpro_link = 5
        others                      = 6
        .
    if sy-subrc <> 0.
*     MESSAGE ID SY-MSGID TYPE SY-MSGTY NUMBER SY-MSGNO
*                WITH SY-MSGV1 SY-MSGV2 SY-MSGV3 SY-MSGV4.
    endif.

    create object ref_alv
      exporting
*        I_SHELLSTYLE      = 0
*        I_LIFETIME        =
        i_parent          = ref_container
*        I_APPL_EVENTS     = space
*        I_PARENTDBG       =
*        I_APPLOGPARENT    =
*        I_GRAPHICSPARENT  =
*        I_NAME            =
*        I_FCAT_COMPLETE   = SPACE
      exceptions
        error_cntl_create = 1
        error_cntl_init   = 2
        error_cntl_link   = 3
        error_dp_create   = 4
        others            = 5
        .
    if sy-subrc <> 0.
*     MESSAGE ID SY-MSGID TYPE SY-MSGTY NUMBER SY-MSGNO
*                WITH SY-MSGV1 SY-MSGV2 SY-MSGV3 SY-MSGV4.
    endif.


  endmethod.

  method get_alv_data.

    clear: gt_alv_data[].

    data: o_ref type ref to if_localazation.
    read table gt_ref with key table_line->bukrs = ref_app->bukrs into o_ref.
    if sy-subrc = 0.
       o_ref->get_alv_data( importing et_ltak = gt_alv_data ).
     endif.
  endmethod.


  method set_alv_data.

    call method ref_alv->set_table_for_first_display
       exporting
*        I_BUFFER_ACTIVE               =
         i_bypassing_buffer            = 'X'
*        I_CONSISTENCY_CHECK           =
*        I_STRUCTURE_NAME              =
*        IS_VARIANT                    =
*        I_SAVE                        =
*        I_DEFAULT                     = 'X'
*        IS_LAYOUT                     =
*        IS_PRINT                      =
*        IT_SPECIAL_GROUPS             =
*        IT_TOOLBAR_EXCLUDING          =
*        IT_HYPERLINK                  =
*        IT_ALV_GRAPHICS               =
*        IT_EXCEPT_QINFO               =
*        IR_SALV_ADAPTER               =
      changing
         it_outtab                     = gt_alv_data
         it_fieldcatalog               = fieldcat
*        IT_SORT                       =
*        IT_FILTER                     =
      exceptions
        invalid_parameter_combination = 1
        program_error                 = 2
        too_many_lines                = 3
        others                        = 4
            .
    if sy-subrc <> 0.
*     MESSAGE ID SY-MSGID TYPE SY-MSGTY NUMBER SY-MSGNO
*                WITH SY-MSGV1 SY-MSGV2 SY-MSGV3 SY-MSGV4.
    endif.

  endmethod.

  method reg_local_obj.
    data: wa_ref like line of gt_ref.

    move sender to wa_ref.
    wa_ref->bukrs = ev_bukrs.
    append wa_ref to gt_ref. clear wa_ref. free wa_ref.
  endmethod.

  method run_application.
    if ref_app is bound.
      exit.
    else.
      create object ref_app exporting iv_bukrs = iv_bukrs .
    endif.
  endmethod.                    "run_application

  method pbo.

    if ref_app is initial.
      exit.
    endif.

    call method ref_app->set_status( 'DISPLAY' ).

  endmethod.     "PBO

  method exit_command.

    ref_app->ok_code = iv_code.

    case ref_app->ok_code.
      when 'BACK' or 'CANC'.
        ref_app->leave_screen( ).
    endcase.
  endmethod.                    "EXIT_COMMAND

  method pai.
    data: o_ref type ref to if_localazation.
    ref_app->ok_code = iv_code.

    case ref_app->ok_code.
      when 'CALC'.
        read table gt_ref with key table_line->bukrs = ref_app->bukrs into o_ref.
        if sy-subrc = 0.
          scr_100-work_days = o_ref->calc_working_days( ).
        endif.

       when 'CHAN'.
         ref_app->set_status( 'CHANGE' ).

      when others.
    endcase.
  endmethod.

  method leave_screen.
    set screen 0.
    leave screen.
  endmethod.                    "LEAVE_SCREEN

  method constructor.
    bukrs = iv_bukrs.

    set handler me->reg_local_obj for all instances.

    create object ref_local_gr.
    create object ref_local_ch.

    call method get_alv_data.
    call method set_alv_data.

    call screen 100.
  endmethod.                    "CONSTRUCTOR

  method set_status.
    screen_status = iv_status.

    set pf-status screen_status.
  endmethod.

  method build_fieldcatalog.
    call function 'LVC_FIELDCATALOG_MERGE'
     exporting
*       I_BUFFER_ACTIVE              =
        i_structure_name             = 'LTAK'
*       I_CLIENT_NEVER_DISPLAY       = 'X'
*       I_BYPASSING_BUFFER           =
*       I_INTERNAL_TABNAME           =
      changing
        ct_fieldcat                  = fieldcat
     exceptions
       inconsistent_interface       = 1
       program_error                = 2
       others                       = 3
              .
    if sy-subrc <> 0.
* MESSAGE ID SY-MSGID TYPE SY-MSGTY NUMBER SY-MSGNO
*         WITH SY-MSGV1 SY-MSGV2 SY-MSGV3 SY-MSGV4.
    endif.

  endmethod.                 "SET_STATUS
endclass.                    "LCL_APP IMPLEMENTATION





*----------------------------------------------------------------------*
*       CLASS lcl_local_gr IMPLEMENTATION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
class lcl_local_gr implementation.
  method constructor.
    raise event if_localazation~obj_created exporting ev_bukrs = '1000'.
  endmethod.

  method if_localazation~init.
    call method if_localazation~calc_working_days.
  endmethod.                    "if_localazation~calc_working_days

  method if_localazation~calc_working_days.
    ev_days = 25.
  endmethod.                    "if_localazation~calc_working_days

  method if_localazation~get_alv_data.
    select * from ltak into table et_ltak
      where lgnum = '010'.
  endmethod.

endclass.                    "lcl_local_gr IMPLEMENTATION

*----------------------------------------------------------------------*
*       CLASS lcl_local_ch IMPLEMENTATION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
class lcl_local_ch implementation.
  method constructor.
    raise event if_localazation~obj_created exporting ev_bukrs = '2000'.
  endmethod.

  method if_localazation~init.
     call method if_localazation~calc_working_days.
  endmethod.                    "if_localazation~if_init

  method if_localazation~calc_working_days.
     ev_days = 19.
  endmethod.                    "if_localazation~calc_working_days

  method if_localazation~get_alv_data.
    select * from ltak into table et_ltak
      where lgnum = 'TRM'.
  endmethod.

endclass.                    "lcl_local_ch IMPLEMENTATION

 

Modules

*&-------------------------------------------------------------------
*&  Include           ZBC_GMICH_04_MODULES
*&-------------------------------------------------------------------
*&---------------------------------------------------------------------*
*&      Module  PBO  OUTPUT
*&---------------------------------------------------------------------*
*       text
*----------------------------------------------------------------------*
module pbo output.

  lcl_app=>pbo( ).

endmodule.                 " PBO  OUTPUT


*&---------------------------------------------------------------------*
*&      Module  PAI  INPUT
*&---------------------------------------------------------------------*
*       text
*----------------------------------------------------------------------*
module pai input.

  lcl_app=>pai( ok_code ).

endmodule.                 " PAI  INPUT


*&---------------------------------------------------------------------*
*&      Module  EXIT_COMMAND  INPUT
*&---------------------------------------------------------------------*
*       text
*----------------------------------------------------------------------*
module exit_command input.

  lcl_app=>exit_command( ok_code ).

endmodule.                 " EXIT_COMMAND  INPUT

 

Special Tips

  • Try to hiding thinks (Private or protected). If there is no reason to expose a method or data of the method, then there is no reason these to be public. We should hide the implementation from the outside world.
  • The Screen Flow logic should be controlled by static methods
  • Screen objects should be created via static method
  • We cannot call an instance method from a static method of the same class.

Initially we are calling a factory method to bring the object into life.

 Factory Method 


lcl_app=>run_application( iv_bukrs = p_bukrs ).

The method takes as an input the company code. This is a static method that will instanciate the application object.

 

Method: run_application – Factroy method of class LCL_APP

method run_application.
    if ref_app is bound.
      exit.
    else.
      create object ref_app exporting iv_bukrs = iv_bukrs .
    endif.
  endmethod.    

This method can be called, because it is static. So there is no need for an excising object of that class. Inside the method we are checking if there is an active object of the class, otherwise we are instantiate the “ref_app”.

 

 

static constructor

method class_constructor.
    call method build_fieldcatalog.
    call method build_screen_object.
  endmethod.

We are building the screen object and the fieldcatalog

 

instance constructor

method constructor.
    bukrs = iv_bukrs.

    set handler me->reg_local_obj for all instances.

    create object ref_local_gr.
    create object ref_local_ch.

    call method get_alv_data.
    call method set_alv_data.

    call screen 100.
  endmethod.     

We are registering the event handler. We are cr instantiate the local business classes for all the individual countries and we are calling the first screen.

 

 

Method: get_alv_data

method get_alv_data.

    clear: gt_alv_data[].

    data: o_ref type ref to if_localazation.
    read table gt_ref with key table_line->bukrs = ref_app->bukrs into o_ref.

    if sy-subrc = 0.
       o_ref->get_alv_data( importing et_ltak = gt_alv_data ).
     endif.
endmethod.

We are use the “Polymorphism” technique to see what is the relevant business class for the specific company code.

3 Comments