
We showed in the earlier article, “Just 4 Versions of the Same Program to Learn OOPs ABAP,” how an ABAPer might transition from procedural to object-oriented programming. We have included the identical program in this post. The selection screen has two SELECT OPTIONS rather than simply one PARAMETER. There are two radio buttons that need to be managed, and two selects for data retrieval will occure.
Let’s examine the current program that is installed on the machine. It displays the traditional report as the output after receiving the transaction code or role as input. Examining the code below, you will see that it combines some outdated programming techniques (traditional reporting and an internal table with header lines) with pure procedural language.
Current Report in the Conventional ABAP Process Method
report sy-repid line-size 151 line-count 65 no standard page heading. *----------------------------------------------------------------------* * Title: Security report - Roles assigned to * Transaction Codes or vice versa. *----------------------------------------------------------------------* * Function: Generates a report of relationships between Transaction * Codes and Security Roles. It has options of switching the * dimensions of the report - i.e. TCODE to ROLE or ROLE to * TCODE *----------------------------------------------------------------------* tables: agr_1251, agr_texts, tstct. *--------------------------------------------------------------------- selection-screen begin of block repopt with frame title text-001. parameters: ptcode radiobutton group ropt. select-options: s_tcode for tstct-tcode. selection-screen skip. parameters: prole radiobutton group ropt. select-options: s_role for agr_1251-agr_name. selection-screen end of block repopt. *--------------------------------------------------------------------- data: begin of t_tcode occurs 0, tcode like agr_1251-low, ttext like tstct-ttext, role like agr_1251-agr_name, rtext like agr_texts-text, end of t_tcode. data: begin of t_role occurs 0, role like agr_1251-agr_name, rtext like agr_texts-text, tcode like agr_1251-low, ttext like tstct-ttext, end of t_role. *--------------------------------------------------------------------- top-of-page. *--------------------------------------------------------------------- format color col_heading. if ptcode = 'X'. write: / sy-repid, 60 'Transaction Code to Role Matrix', 136 'Date:', sy-datum. write: /136 'Page:', (10) sy-pagno no-sign. uline. write: /(20) 'Txn Code', (36) 'Txn Desc', 60(30)'Role Name', (61) 'Role Desc'. uline. else. write: / sy-repid, 60 'Role to Transaction Code Matrix', 136 'Date:', sy-datum. write: /136 'Page:', (10) sy-pagno no-sign. uline. write: /(30) 'Role Name', (61) 'Role Desc', (20) 'Txn Code', (37) 'Txn Desc'. uline. endif. format color off. *--------------------------------------------------------------------- start-of-selection. if ptcode = 'X'. perform report_by_tcode. else. perform report_by_role. endif. *--------------------------------------------------------------------- *&---------------------------------------------------------------------* *& Form report_by_tcode *&---------------------------------------------------------------------* * Generate report of Roles assigned to TCODEs *----------------------------------------------------------------------* form report_by_tcode. select a~low b~ttext a~agr_name c~text into table t_tcode from agr_1251 as a inner join tstct as b on a~low = b~tcode inner join agr_texts as c on a~agr_name = c~agr_name where a~low in s_tcode and a~object = 'S_TCODE' and b~sprsl = sy-langu and c~spras = sy-langu and c~line = '00000' order by a~low a~agr_name. loop at t_tcode. * at new ttext. write: /(20) t_tcode-tcode, t_tcode-ttext. * endat. write: 60 t_tcode-role, (61) t_tcode-rtext. new-line. at end of ttext. skip. endat. endloop. endform. " report_by_tcode *&---------------------------------------------------------------------* *& Form report_by_role *&---------------------------------------------------------------------* * Generate report of TCODEs assigned to Roles *----------------------------------------------------------------------* form report_by_role. select a~agr_name c~text a~low b~ttext into table t_role from agr_1251 as a inner join tstct as b on a~low = b~tcode inner join agr_texts as c on a~agr_name = c~agr_name where a~agr_name in s_role and a~object = 'S_TCODE' and b~sprsl = sy-langu and c~spras = sy-langu and c~line = '00000' order by a~agr_name a~low. loop at t_role. * at new rtext. write: / t_role-role, (61) t_role-rtext. * endat. write: 94(20) t_role-tcode, t_role-ttext. new-line. at end of rtext. skip. endat. endloop. endform. " report_by_role
Let us execute the program and see the output.
Also Read: Back to Basic
I am sure, all of you know OOPs concepts and theories right from your school and college days where you learnt C, C++ or Java. But destiny made you work in procedural ABAP. Here, we would not speak about theory. Just look at the above code and start writing your own OOPs program which would do the same thing as the above report. Plan out how you would handle the INITIALIZATION. Do you need any global/public attributes (variables)? Can we reuse one object instance in another object? After all that is one core fundamentals of OOPs.
If you have read the previous post on OOPs ABAP, you already know that we have divided our report into three local classes (roughly to follow MVC – Model View Controller Architecture). Class 1 for Selection parameter, Class 2 for Data Fetching and Class 3 for Display.
Before we proceed, let me show you two code snippets.
What is the difference between method FACTORY and VALIDATE_INPUT in the below OOPs Report?
Why is FACTORY method called using ‘=>’ but VALIDATE_INPUT using ‘->’ ?
You guessed it right. One is a STATIC method and another is INSTANCE method. STATIC is called using ‘=>’. You will know this only if you start coding. So log into your system as soon as you get time and try to call one STATIC and one INSTANCE method in a test program.
Read more: Static and Instance Method difference.
CALL METHOD cl_salv_table=>factory IMPORTING r_salv_table = me->o_salv_display CHANGING t_table = me->o_rep_fet->t_tcode.
t_table = me->o_rep_fet->t_tcode. o_selection->validate_input( EXPORTING ip_tcode_flag = ptcode ip_role_flag = prole ).
Let us look another section of the program. Why is there no EXPORTING while creating object O_SELECTION, while O_FETCH and O_DISPLAY has EXPORTING parameters? Child’s play for experienced OOPs ABAP. Please do not laugh at me if you think it is too silly.
Answer for the newbies. We always read in theory, CONSTRUCTOR method is called the moment we create the OBJECT instance. Class LCL_REPORT_FETCH and LCL_REPORT_DISPLAY both have CONSTRUCTOR method which needs some IMPORTING parameters. If you do not pass those parameters while creating the Object, your code will not be syntactically correct.
You need to log into SAP system now. Try the code yourself to see it. These are simple stuff which we cannot learn by reading PPTs and PDFs. We need to make our hands dirty.
*---------------------------------------------------------------------* * INITIALIZATION * *---------------------------------------------------------------------* INITIALIZATION. CREATE OBJECT o_selection. CREATE OBJECT o_fetch EXPORTING io_rep_sel = o_selection. CREATE OBJECT o_display EXPORTING io_rep_fetch = o_fetch.
Finally, why did we NOT default the public attribute (variable) of class LCL_REPORT_SELECTION at INITIALIZATION? Simple, users enter the selection screen options after INITIALIZATION is done. So AT SELECTION-SCREEN is the right place to capture the screen values. Too basic, but not sure why I felt like tell this too.
*----------------------------------------------------------------------* * AT SELECTION-SCREEN. *----------------------------------------------------------------------* AT SELECTION-SCREEN. * Pass to public variables of the class o_selection->gt_tcode[] = s_tcode[]. o_selection->gt_role[] = s_role[].
Rest all code is pretty straight forward. Give special attention to the CONSTRUCTOR methods of FETCH and DISPLAY class. We have passed the whole object data of SELECTION class to FETCH object. Similarly, the complete data of FETCH object is passed to DISPLAY.
* +---------------------------------------------------------------------------------------+ * | Instance Public Method LCL_REPORT_FETCH->CONSTRUCTOR * +---------------------------------------------------------------------------------------+ * +---------------------------------------------------------------------------------------+ METHOD constructor. me->o_rep_sel = io_rep_sel. ENDMETHOD.
* +---------------------------------------------------------------------------------------+ * | Instance Public Method YCL_REPORT_DISPLAY->CONSTRUCTOR * +---------------------------------------------------------------------------------------+ * +---------------------------------------------------------------------------------------+ METHOD constructor. me->o_rep_fet = io_rep_fetch. ENDMETHOD.
Put the breakpoint at both the CONSTRUCTOR methods. Execute the program and check that the SELECTION object and FETCH object during INITIALIZATION is blank in the two CONSTRUCTOR methods but the container is ready. When you use the other method for FETCH object, the SELECTION container which was blank in INITIALIZATION has data in the container. That is the beauty of OOPs. It is like Pointers in C. The address is populated with the actual data.
Also Read: 15 minutes Videos per session for ABAP OOPs Refresher
Check at initialization, the SELECTION object attributes are empty/blank. But the container is ready.
When the program goes to SELECTION SCREEN, we have logic in place to populate SELECTION object attributes. But we do not pass this attribute explicitly again to FETCH object. But, when we are in another method of FETCH, the SELECTION object attribute which was initialized in CONSTRUCTOR method of FETCH is already populated. This is one concept of OOPs which we have unknowingly used. You need to debug for more clarity.
i.e. the CONTAINER for FETCH which was created in the CONSTRUCTOR method of FETCH during CREATE OBJECT command is automatically populated as soon as the O_SELECTION OBJECT populates the data.
Enough of trailers. Let us reveal the full movie. Please go through the code below. Try to debug every step and understand the concept. I am sure, this is not the best OOPs programming, but it should be sound enough for beginners like me.
Interested in HANA? Check, SAP HANA for Beginners from a Beginner.
I would like to call upon all experienced OOPs ABAP and enthusiast to point out the issues in the below OOPs Report. Please reveal, how we could have made the Report better in OOPs. Please leave your suggestions so that our freshers in OOPs ABAP could learn from your experience and knowledge.
Same Report in OOPs ABAP.
*----------------------------------------------------------------------* * Date: Sept 2016 * Author: www.sapyard.com * Title: Security report - Roles assigned to * Transaction Codes or vice versa. *----------------------------------------------------------------------* * Desc : Generates a report of relationships between Transaction * Codes and Security Roles. It has options of switching the * dimensions of the report - i.e. TCODE to ROLE or ROLE to * TCODE *----------------------------------------------------------------------* * ABAPer who just wrote his Second OOPs development nearly corret *----------------------------------------------------------------------* REPORT zsr_tcode_role_matrix_in_oops LINE-SIZE 151 LINE-COUNT 65 NO STANDARD PAGE HEADING. * +---------------------------------------------------------------------------------------+ * | LCL_REPORT_SELECTION Definition * +---------------------------------------------------------------------------------------+ CLASS lcl_report_selection DEFINITION. PUBLIC SECTION. TYPES: rt_tcode TYPE RANGE OF tstct-tcode.. TYPES: rt_role TYPE RANGE OF agr_1251-agr_name. DATA gt_tcode TYPE rt_tcode . DATA gt_role TYPE rt_role . DATA g_langu TYPE spras . DATA g_object TYPE agobject . DATA g_line TYPE menu_num_5 . DATA g_tcode_or_role TYPE flag. METHODS validate_input IMPORTING ip_tcode_flag TYPE flag ip_role_flag TYPE flag. METHODS validate_tcode. METHODS validate_role. PROTECTED SECTION. PRIVATE SECTION. ENDCLASS. * +---------------------------------------------------------------------------------------+ * | LCL_REPORT_SELECTION Implementation * +---------------------------------------------------------------------------------------+ CLASS lcl_report_selection IMPLEMENTATION. * +---------------------------------------------------------------------------------------+ * | Instance Public Method LCL_REPORT_SELECTION->VALIDATE_INPUT * +---------------------------------------------------------------------------------------+ * +--------------------------------------------------------------------------------------- METHOD validate_input. IF ip_tcode_flag = abap_true. validate_tcode( ). ELSEIF ip_role_flag = abap_true. validate_role( ). ENDIF. ENDMETHOD. METHOD validate_tcode. SELECT COUNT(*) UP TO 1 ROWS FROM tstc WHERE tcode IN gt_tcode. IF sy-subrc NE 0. MESSAGE 'Please enter a Valid T-Code' TYPE 'E'. ELSE. * Populate the global variable g_langu = sy-langu. g_object = 'S_TCODE'. g_line = '00000'. ENDIF. ENDMETHOD. METHOD validate_role. SELECT COUNT(*) UP TO 1 ROWS FROM agr_define WHERE agr_name IN gt_role. IF sy-subrc NE 0. MESSAGE 'Please enter a Valid Role' TYPE 'E'. ELSE. * Populate the global variable g_langu = sy-langu. g_object = 'S_TCODE'. g_line = '00000'. ENDIF. ENDMETHOD. ENDCLASS. * +---------------------------------------------------------------------------------------+ * | LCL_REPORT_FETCH Definition * +---------------------------------------------------------------------------------------+ CLASS lcl_report_fetch DEFINITION. PUBLIC SECTION. TYPES: *----------------------------------------------------------------------* * TYPE Declaration *----------------------------------------------------------------------* BEGIN OF ty_tcode, tcode TYPE tcode, " Transaction ttext TYPE ttext_stct, " Transaction Text role TYPE agr_name, " Role Name rtext TYPE agr_title, " Short Description END OF ty_tcode . TYPES: tt_tcode TYPE STANDARD TABLE OF ty_tcode . DATA o_rep_sel TYPE REF TO lcl_report_selection . DATA t_tcode TYPE tt_tcode . METHODS fetch_data IMPORTING ip_tcode_flag TYPE flag ip_role_flag TYPE flag. METHODS fetch_by_tcode IMPORTING ip_tcode_flag TYPE flag. METHODS fetch_by_role IMPORTING ip_role_flag TYPE flag. METHODS constructor IMPORTING !io_rep_sel TYPE REF TO lcl_report_selection . PROTECTED SECTION. PRIVATE SECTION. ENDCLASS. * +---------------------------------------------------------------------------------------+ * | LCL_REPORT_FETCH Implementation * +---------------------------------------------------------------------------------------+ CLASS lcl_report_fetch IMPLEMENTATION. * +---------------------------------------------------------------------------------------+ * | Instance Public Method LCL_REPORT_FETCH->CONSTRUCTOR * +---------------------------------------------------------------------------------------+ * +--------------------------------------------------------------------------------------- METHOD constructor. me->o_rep_sel = io_rep_sel. ENDMETHOD. * +---------------------------------------------------------------------------------------+ * | Instance Public Method LCL_REPORT_FETCH->FETCH_DATA * +---------------------------------------------------------------------------------------+ * +--------------------------------------------------------------------------------------- METHOD fetch_data. fetch_by_tcode( ip_tcode_flag ). fetch_by_role( ip_role_flag ). ENDMETHOD. METHOD fetch_by_tcode. IF ip_tcode_flag = abap_true. SELECT a~low b~ttext a~agr_name c~text INTO TABLE t_tcode FROM agr_1251 AS a INNER JOIN tstct AS b ON a~low = b~tcode INNER JOIN agr_texts AS c ON a~agr_name = c~agr_name WHERE a~low IN me->o_rep_sel->gt_tcode AND a~object = me->o_rep_sel->g_object AND b~sprsl = me->o_rep_sel->g_langu AND c~spras = me->o_rep_sel->g_langu AND c~line = me->o_rep_sel->g_line ORDER BY a~low a~agr_name. ENDIF. ENDMETHOD. METHOD fetch_by_role. IF ip_role_flag = abap_true. SELECT a~low b~ttext a~agr_name c~text INTO TABLE t_tcode FROM agr_1251 AS a INNER JOIN tstct AS b ON a~low = b~tcode INNER JOIN agr_texts AS c ON a~agr_name = c~agr_name WHERE a~agr_name IN me->o_rep_sel->gt_role AND a~object = me->o_rep_sel->g_object AND b~sprsl = me->o_rep_sel->g_langu AND c~spras = me->o_rep_sel->g_langu AND c~line = me->o_rep_sel->g_line ORDER BY a~low a~agr_name. ENDIF. ENDMETHOD. ENDCLASS. * +---------------------------------------------------------------------------------------+ * | LCL_REPORT_DISPLAY Definition * +---------------------------------------------------------------------------------------+ CLASS lcl_report_display DEFINITION. PUBLIC SECTION. DATA o_rep_fet TYPE REF TO lcl_report_fetch . DATA o_salv_display TYPE REF TO cl_salv_table. METHODS display_alv . METHODS constructor IMPORTING !io_rep_fetch TYPE REF TO lcl_report_fetch . PROTECTED SECTION. PRIVATE SECTION. ENDCLASS. * +---------------------------------------------------------------------------------------+ * | LCL_REPORT_DISPLAY Implementation * +---------------------------------------------------------------------------------------+ CLASS lcl_report_display IMPLEMENTATION. * +---------------------------------------------------------------------------------------+ * | Instance Public Method YCL_REPORT_DISPLAY->CONSTRUCTOR * +---------------------------------------------------------------------------------------+ * +--------------------------------------------------------------------------------------- METHOD constructor. me->o_rep_fet = io_rep_fetch. ENDMETHOD. * +---------------------------------------------------------------------------------------+ * | Instance Public Method YCL_REPORT_DISPLAY->DISPLAY_ALV * +---------------------------------------------------------------------------------------+ * +--------------------------------------------------------------------------------------- METHOD display_alv. TRY. CALL METHOD cl_salv_table=>factory IMPORTING r_salv_table = me->o_salv_display CHANGING t_table = me->o_rep_fet->t_tcode. me->o_salv_display->display( ). CATCH cx_salv_msg . ENDTRY. ENDMETHOD. ENDCLASS. *----------------------------------------------------------------------* * TABLES declaration *----------------------------------------------------------------------* TABLES: agr_1251, agr_texts, tstct. *----------------------------------------------------------------------* * Define the Object Data *----------------------------------------------------------------------* DATA: o_selection TYPE REF TO lcl_report_selection, o_fetch TYPE REF TO lcl_report_fetch, o_display TYPE REF TO lcl_report_display. *----------------------------------------------------------------------* * SELECTION SCREEN *----------------------------------------------------------------------* SELECTION-SCREEN BEGIN OF BLOCK repopt WITH FRAME TITLE text-001. PARAMETERS: ptcode RADIOBUTTON GROUP ropt. SELECT-OPTIONS: s_tcode FOR tstct-tcode. SELECTION-SCREEN SKIP. PARAMETERS: prole RADIOBUTTON GROUP ropt. SELECT-OPTIONS: s_role FOR agr_1251-agr_name. SELECTION-SCREEN END OF BLOCK repopt. *---------------------------------------------------------------------* * INITIALIZATION * *---------------------------------------------------------------------* INITIALIZATION. CREATE OBJECT o_selection. CREATE OBJECT o_fetch EXPORTING io_rep_sel = o_selection. CREATE OBJECT o_display EXPORTING io_rep_fetch = o_fetch. *----------------------------------------------------------------------* * AT SELECTION-SCREEN. *----------------------------------------------------------------------* AT SELECTION-SCREEN. * Pass to public variables of the class o_selection->gt_tcode[] = s_tcode[]. o_selection->gt_role[] = s_role[]. * Validation at Selection Screen o_selection->validate_input( EXPORTING ip_tcode_flag = ptcode ip_role_flag = prole ). *----------------------------------------------------------------------* * START-OF-SELECTION *----------------------------------------------------------------------* START-OF-SELECTION. o_fetch->fetch_data( EXPORTING ip_tcode_flag = ptcode ip_role_flag = prole ). **----------------------------------------------------------------------* ** END-OF-SELECTION **----------------------------------------------------------------------* START-OF-SELECTION. o_display->display_alv( ).
Needless to say, the output would be same. We are displaying an ALV report instead of classical report.
No habit can be changed quickly. In a similar vein, an ABAPer used to procedural language would find it difficult to adjust to OOPs ABAP within a few days. Making improvements to oneself and learning from mistakes is an ongoing process.
Thus, don’t delay any longer. Start with a few extremely simple OOP apps. So let’s develop the habit of switching from procedural to object-oriented thinking.
What more would you like to add to this article? Have there been any problems using OOPs? Would you like to share any actual project specifications or solutions?Please don’t hesitate to speak up.Kindly share your opinions in the space provided for comments.
We adore hearing from you.Please share your thoughts, both positive and negative.
I sincerely appreciate your time!
YOU MAY BE INTERESTED IN