In this blog, I will not be discussing about Object Oriented Concepts and theory as there are many documents and information available regarding the same. I am gonna discuss about how to start thinking in object oriented rather than procedural approach, how to implement or use the object oriented concepts while writing your code by benefiting your code performance, making your code compact and more reusable etc.
THINK OO
It is easy for an ABAPer who has been coding in ABAP(procedural) to code in ABAP OO by defining a local class and using methods instead of performs but that is not object oriented! To make use of object oriented concepts, you need to think OO. Think of what you need to develop in your code as objects.
You need to first design the requirement in Object oriented then it will be easy when you start coding.
For e.g. if you need to develop a report which displays a header and item alv then consider a parent class alv which has all the common attributes and methods which are inherited by 2 sub classes header and item alv. you can define the methods that are common for both in the parent class and methods that are different in each of the sub classes.
CODING IN OO
After designing when you are coding in OO, make use of the following points:
SAMPLE PROGRAM CODE
To develop a Report for Purchase order using ABAP OOPS.
Three radio button
As per the feedback and comments I have received from all of you, I have corrected my code. I hope that I have been able to remove the flaws in my previous design. I am not posting screen shots this time as one complained that it disables them to copy paste my code if they want to try it.
In the main program, you can see that I have separated various parts of the code inside includes. It is not recommended to add an include unless there is at least 200 lines of code but top of page/ data definitions is usually written inside the include as the variables/objects can be reused by other programs in the package(I have very few definitions and hence I have removed the data definitions include).
REPORT ZPO_OOPS.
TABLES: ekko.
INCLUDE ZPO_OOPS_SS. "Selection Screen
INCLUDE ZPO_OOPS_CDI. "Class Definitions and Implementations
DATA: o_purchaseorder TYPE REF TO cl_purchaseorder,
o_cont1 TYPE REF TO cl_gui_custom_container,
o_cont2 TYPE REF TO cl_gui_custom_container,
o_grid1 TYPE REF TO cl_gui_alv_grid,
o_grid2 TYPE REF TO cl_gui_alv_grid.
INCLUDE ZPO_OOPS_PBO. "PBO Modules
INCLUDE ZPO_OOPS_PAI. "PAI Modules
START-OF-SELECTION.
CREATE OBJECT: o_purchaseorder.
CALL METHOD o_purchaseorder->select_po.
Class definition deferred statement is used when we create the objects of the class before the actual definition and implementation. This way the debugger will come to know that the definition is written later in the code. If we do not define it later on then it will show an error.( I do not need to use the deferred statement here as I have declared classes after the definition).
Selection screen
SELECTION-SCREEN: BEGIN OF BLOCK po WITH FRAME TITLE text-009.
SELECT-OPTIONS: s_ebeln FOR ekko-ebeln,
s_aedat FOR ekko-aedat.
SELECTION-SCREEN: END OF BLOCK po.
SELECTION-SCREEN: BEGIN OF BLOCK rb WITH FRAME TITLE text-010.
SELECTION-SCREEN: BEGIN OF LINE.
PARAMETERS: r_releas RADIOBUTTON GROUP r1.
SELECTION-SCREEN COMMENT 2(15) text-000 FOR FIELD r_releas.
PARAMETERS: r_reject RADIOBUTTON GROUP r1.
SELECTION-SCREEN COMMENT 20(15) text-001 FOR FIELD r_reject.
PARAMETERS: r_no_rel RADIOBUTTON GROUP r1.
SELECTION-SCREEN COMMENT 40(17) text-002 FOR FIELD r_no_rel.
SELECTION-SCREEN: END OF LINE.
SELECTION-SCREEN: END OF BLOCK rb.
I have used a controller interface just to separate the methods used for alv display.
INTERFACE i_controller.
METHODS: alv_display EXPORTING cont TYPE REF TO cl_gui_custom_container
grid TYPE REF TO cl_gui_alv_grid
name TYPE scrfname,
fc_header,
on_click FOR EVENT hotspot_click
OF cl_gui_alv_grid
IMPORTING e_row_id.
ENDINTERFACE. "Interface for output
I have used one Purchase order class where the attributes and methods that are accessed by the program directly are declared in the Public section and the attributes that are used inside methods of the class are declared under Private section(Encapsulation). Class-constructor is used when you want to initiate the attributes when the class is accessed the first time. In this case I am assigning the layout structure initially.
*----------------------------------------------------------------------*
* CLASS cl_purchaseorder DEFINITION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS cl_purchaseorder DEFINITION.
PUBLIC SECTION.
CONSTANTS: lc_cont1 TYPE scrfname VALUE 'HEAD_CON',
lc_cont2 TYPE scrfname VALUE 'ITEM_CON'.
DATA: lv_cont TYPE scrfname.
DATA: lt_ekko TYPE STANDARD TABLE OF zpo_st_ekko,
lt_ekpo TYPE STANDARD TABLE OF zpo_st_ekpo.
DATA: lt_ekko_tmp TYPE STANDARD TABLE OF zpo_st_ekko.
CLASS-DATA: ok_code TYPE syucomm.
CLASS-DATA: lx_layout TYPE lvc_s_layo.
DATA: lt_fcat TYPE lvc_t_fcat.
CLASS-METHODS: class_constructor.
INTERFACES: i_controller.
ALIASES: alv_display FOR i_controller~alv_display,
fc_header FOR i_controller~fc_header,
on_click FOR i_controller~on_click.
METHODS: select_po,
save,
back,
exit.
PRIVATE SECTION.
CONSTANTS: lc_procstat1 TYPE meprocstate VALUE '01',
lc_procstat4 TYPE meprocstate VALUE '04',
lc_procstat5 TYPE meprocstate VALUE '05',
lc_procstat6 TYPE meprocstate VALUE '06'.
DATA: lv_ans TYPE c.
DATA: lv_procstat1 TYPE meprocstate,
lv_procstat2 TYPE meprocstate.
DATA: lx_fcat TYPE lvc_s_fcat.
DATA: lx_ekko TYPE zpo_st_ekko,
lx_ekko_tmp TYPE zpo_st_ekko.
DATA: lt_fieldcat TYPE slis_t_fieldcat_alv,
lx_fieldcat TYPE slis_fieldcat_alv.
ENDCLASS. "cl_purchaseorder DEFINITION
I am created structures in the database to avoid building the field catalog, used the FM 'REUSE_ALV_FIELDCATALOG_MERGE' to get field catalog of a structure in order to modify it for hotspot and to make a field editable. Event hotspot_click is used for the method on_click. When we call set handler for this event, the method gets called each time the event is triggered. Constructor is called initially when the object of a class is created.
*----------------------------------------------------------------------*
* CLASS cl_purchaseorder IMPLEMENTATION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS cl_purchaseorder IMPLEMENTATION.
METHOD class_constructor.
lx_layout-zebra = 'X'.
lx_layout-cwidth_opt = 'X'.
ENDMETHOD. "class_constructor
METHOD alv_display.
CREATE OBJECT cont
EXPORTING
container_name = name.
CREATE OBJECT grid
EXPORTING
i_parent = cont.
ENDMETHOD. "alv_display
METHOD select_po.
IF r_releas EQ 'X'.
lv_procstat1 = lc_procstat5.
lv_procstat2 = lc_procstat5.
ELSEIF r_reject EQ 'X'.
lv_procstat1 = lc_procstat5.
lv_procstat2 = lc_procstat6.
ELSEIF r_no_rel EQ 'X'.
lv_procstat1 = lc_procstat1.
lv_procstat2 = lc_procstat4.
ENDIF.
SELECT ebeln
bukrs
description
bstyp
bsart
aedat
ernam
FROM ekko
INTO TABLE lt_ekko
WHERE ebeln IN s_ebeln
AND aedat IN s_aedat
AND procstat BETWEEN lv_procstat1 AND lv_procstat2.
IF lt_ekko IS NOT INITIAL.
lt_ekko_tmp[] = lt_ekko[].
CALL SCREEN 9000.
ELSE.
MESSAGE s000(8i) WITH text-011 DISPLAY LIKE 'E'.
ENDIF.
ENDMETHOD. "select_po
METHOD back.
CALL FUNCTION 'POPUP_TO_CONFIRM'
EXPORTING
text_question = text-006
text_button_1 = text-007 "'Ja'(001)
text_button_2 = text-008"'Nein'(002)
IMPORTING
answer = lv_ans
EXCEPTIONS
text_not_found = 1
OTHERS = 2.
IF sy-subrc EQ 0.
CASE lv_ans.
WHEN '1'.
CALL METHOD me->save.
LEAVE TO SCREEN 0.
WHEN '2'.
LEAVE TO SCREEN 0.
WHEN 'X'.
ENDCASE.
ENDIF.
ENDMETHOD. "back
METHOD exit.
CALL FUNCTION 'POPUP_TO_CONFIRM'
EXPORTING
text_question = text-006
text_button_1 = text-007 "'Ja'(001)
text_button_2 = text-008"'Nein'(002)
IMPORTING
answer = lv_ans
EXCEPTIONS
text_not_found = 1
OTHERS = 2.
IF sy-subrc EQ 0.
CASE lv_ans.
WHEN '1'.
CALL METHOD me->save.
LEAVE PROGRAM.
WHEN '2'.
LEAVE PROGRAM.
WHEN 'X'.
ENDCASE.
ENDIF.
ENDMETHOD. "constructor
METHOD save.
LOOP AT lt_ekko_tmp INTO lx_ekko_tmp.
READ TABLE lt_ekko INTO lx_ekko WITH KEY ebeln = lx_ekko_tmp-ebeln.
IF sy-subrc EQ 0.
IF lx_ekko-description NE lx_ekko_tmp-description.
UPDATE ekko
SET description = lx_ekko-description
WHERE ebeln = lx_ekko-ebeln.
IF sy-subrc EQ 0.
MESSAGE s000(8i) WITH text-005.
ENDIF.
ENDIF.
ENDIF.
ENDLOOP.
lt_ekko_tmp[] = lt_ekko[].
ENDMETHOD. "save
METHOD fc_header.
CALL FUNCTION 'REUSE_ALV_FIELDCATALOG_MERGE'
EXPORTING
i_structure_name = 'ZPO_ST_EKKO'
CHANGING
ct_fieldcat = lt_fieldcat
EXCEPTIONS
inconsistent_interface = 1
program_error = 2
OTHERS = 3.
LOOP AT lt_fieldcat INTO lx_fieldcat.
MOVE-CORRESPONDING lx_fieldcat TO lx_fcat.
lx_fcat-coltext = lx_fieldcat-seltext_l.
IF lx_fcat-fieldname = 'EBELN'.
lx_fcat-hotspot = 'X'.
ELSEIF lx_fcat-fieldname = 'DESCRIPTION'.
lx_fcat-edit = 'X'.
ENDIF.
APPEND lx_fcat TO lt_fcat.
ENDLOOP.
ENDMETHOD. "fc
METHOD on_click.
READ TABLE lt_ekko INTO lx_ekko INDEX e_row_id-index.
IF sy-subrc EQ 0.
SELECT ebelp
werks
lgort
aedat
txz01
matnr
FROM ekpo
INTO TABLE lt_ekpo
WHERE ebeln = lx_ekko-ebeln.
IF sy-subrc EQ 0.
CALL SCREEN 9001.
ENDIF.
ENDIF.
ENDMETHOD. "on_click
ENDCLASS. "cl_purchaseorder IMPLEMENTATION
PBO
*&---------------------------------------------------------------------*
*& Include ZPO_OOPS_PBO
*&---------------------------------------------------------------------*
*&---------------------------------------------------------------------*
*& Module STATUS_9000 OUTPUT
*&---------------------------------------------------------------------*
* Header screen
*----------------------------------------------------------------------*
MODULE status_9000 OUTPUT.
SET PF-STATUS 'STATUS_9000'.
SET TITLEBAR 'TITLE_9000'.
IF o_grid1 IS INITIAL.
o_purchaseorder->lv_cont = o_purchaseorder->lc_cont1.
CALL METHOD o_purchaseorder->alv_display
IMPORTING
cont = o_cont1
grid = o_grid1
name = o_purchaseorder->lv_cont.
CALL METHOD o_purchaseorder->fc_header.
CALL METHOD o_grid1->set_table_for_first_display
EXPORTING
is_layout = o_purchaseorder->lx_layout
* i_structure_name = 'ZPO_ST_EKKO'
CHANGING
it_outtab = o_purchaseorder->lt_ekko
it_fieldcatalog = o_purchaseorder->lt_fcat.
SET HANDLER o_purchaseorder->on_click FOR o_grid1.
ELSE.
CALL METHOD o_grid1->refresh_table_display.
ENDIF.
ENDMODULE. " STATUS_9000 OUTPUT
*&---------------------------------------------------------------------*
*& Module STATUS_9001 OUTPUT
*&---------------------------------------------------------------------*
* Item Screen
*----------------------------------------------------------------------*
MODULE status_9001 OUTPUT.
SET PF-STATUS 'STATUS_9000' EXCLUDING 'SAVE'.
SET TITLEBAR 'TITLE_9001'.
IF o_grid2 IS INITIAL.
o_purchaseorder->lv_cont = o_purchaseorder->lc_cont2.
CALL METHOD o_purchaseorder->alv_display
IMPORTING
cont = o_cont2
grid = o_grid2
name = o_purchaseorder->lv_cont.
CALL METHOD o_grid2->set_table_for_first_display
EXPORTING
is_layout = o_purchaseorder->lx_layout
i_structure_name = 'ZPO_ST_EKPO'
CHANGING
it_outtab = o_purchaseorder->lt_ekpo.
ELSE.
CALL METHOD o_grid2->refresh_table_display.
ENDIF.
ENDMODULE. " STATUS_9001 OUTPUT
PAI
*&---------------------------------------------------------------------*
*& Include ZPO_OOPS_PAI
*&---------------------------------------------------------------------*
*&---------------------------------------------------------------------*
*& Module USER_COMMAND_9000 INPUT
*&---------------------------------------------------------------------*
* text
*----------------------------------------------------------------------*
MODULE user_command_9000 INPUT.
CASE cl_purchaseorder=>ok_code.
WHEN 'BACK'.
CALL METHOD o_grid1->check_changed_data.
IF o_purchaseorder->lt_ekko_tmp NE o_purchaseorder->lt_ekko.
CALL METHOD o_purchaseorder->back.
ELSE.
LEAVE TO SCREEN 0.
ENDIF.
WHEN 'EXIT' OR 'CANCEL'.
CALL METHOD o_grid1->check_changed_data.
IF o_purchaseorder->lt_ekko_tmp NE o_purchaseorder->lt_ekko.
CALL METHOD o_purchaseorder->exit.
ELSE.
LEAVE PROGRAM.
ENDIF.
WHEN 'SAVE'.
CALL METHOD o_grid1->check_changed_data.
IF o_purchaseorder->lt_ekko_tmp NE o_purchaseorder->lt_ekko.
CALL METHOD o_purchaseorder->save.
ELSE.
MESSAGE s000(8i) WITH text-012 DISPLAY LIKE 'E'.
ENDIF.
ENDCASE.
ENDMODULE. " USER_COMMAND_9000 INPUT
*&---------------------------------------------------------------------*
*& Module USER_COMMAND_9001 INPUT
*&---------------------------------------------------------------------*
* text
*----------------------------------------------------------------------*
MODULE user_command_9001 INPUT.
CASE cl_purchaseorder=>ok_code.
WHEN 'BACK'.
LEAVE TO SCREEN 0.
WHEN 'EXIT' OR 'CANCEL'.
CALL METHOD o_grid2->check_changed_data.
IF o_purchaseorder->lt_ekko_tmp NE o_purchaseorder->lt_ekko.
CALL METHOD o_purchaseorder->exit.
ELSE.
LEAVE PROGRAM.
ENDIF.
ENDCASE.
ENDMODULE. " USER_COMMAND_9001 INPUT
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
User | Count |
---|---|
5 | |
4 | |
3 | |
2 | |
2 | |
2 | |
2 | |
1 | |
1 | |
1 |