Learn SAP from the Experts | The SAP PRESS Blog

Working with the ABAP Prototype Design Pattern

Written by SAP PRESS | Feb 3, 2020 4:00:00 PM

When it comes to cloning items in an ABAP system, you might use a prototype design pattern to accomplish the copying.

 

In this example, we will work on an imaginary purchase requisition application where the user has to enter the vendor code (LIFNR), material number (MATNR), unit price (PREIS and WAERS), and quantity (MENGE and MEINS) into the GUI. We will want it to be possible to enter multiple line items.

 

Brand-New Instances

Below demonstrates what the model class of such an application would roughly look like.

 

CLASS zcl_purchase DEFINITION

PUBLIC FINAL CREATE PUBLIC.

 

PUBLIC SECTION.

“ Some type definitions

 

METHODS add_line IMPORTING !is_line TYPE t_line.

METHODS load_from_db IMPORTING !iv_docno TYPE zdocno.

METHODS save_to_db.

 

PRIVATE SECTION.

“ Some hidden variables

“ Some boring methods

PROTECTED SECTION.

ENDCLASS.

 

CLASS zcl_purchase IMPLEMENTATION.

 

METHOD add_line.

APPEND VALUE #(

obj_material = NEW zcl_material( is_line-matnr )

lifnr = is_line-lifnr

matnr = is_line-matnr

price = VALUE #(

preis = is_line-preis

waers = is_line-waers )

quan = VALUE #(

menge = is_line-menge

meins = is_line-meins )

) TO gt_line.

ENDMETHOD.

 

METHOD load_from_db.

“ Some boring code containing SELECT, etc.

ENDMETHOD.

 

METHOD save_to_db.

“ Some boring code containing MODIFY, etc.

ENDMETHOD.

 

ENDCLASS.

 

So far, so good. As you see, GT_LINE is a nested internal table with five fields: one object (OBJ_MATERIAL); two variables (LIFNR, MATNR); and two work areas (PRICE, QUAN). At this point, we will assume that creating a new CL_MATERIAL has a high runtime cost, which means that CL_MATERIAL~CONSTRUCTOR contains costly code snippets that take quite some time to execute.

 

Below demonstrates what the CL_MATERIAL class looks like.

 

CLASS zcl_material DEFINITION

PUBLIC FINAL CREATE PUBLIC.

 

PUBLIC SECTION.

“ Some type definitions

 

METHODS constructor IMPORTING !iv_matnr TYPE matnr.

“ Some further methods

 

PRIVATE SECTION.

“ Some hidden methods

PROTECTED SECTION.

ENDCLASS.

 

CLASS zcl_material IMPLEMENTATION.

 

METHOD constructor.

“ Some very slow but unavoidable code

ENDMETHOD.

 

“ Some more methods

ENDCLASS.

 

If the user enters a new line item containing a brand new material, we must call ADD_LINE again. Thus, because we will be creating a new instance of CL_MATERIAL we will have to endure high runtime cost. On the other hand, what if the user enters a material number that he/she had entered before? Would we still create a brand new instance of CL_MATERIAL? With our current code, we would. So we must ask ourselves, “Is there a better way?”

 

Luckily there is! What we will do is clone an existing material object instead of creating a new one—the core logic of the prototype design pattern.

 

Item Clone

Let’s look at the Unified Modeling Language (UML) diagram below to see what this should look like.

 

 

The UML diagram has only one extra method: CLONE. This method will do exactly what it says: clone the object. That’s the easy part; the relatively tricky part will transpire in CL_PURCHASE. Let’s start simple and see what CL_MATERIAL looks like below.

 

CLASS zcl_material DEFINITION

PUBLIC FINAL CREATE PUBLIC.

 

PUBLIC SECTION.

“ Some type definitions

 

METHODS constructor IMPORTING !iv_matnr TYPE matnr.

METHODS clone RETURNING VALUE(ro_material) TYPE REF TO zcl_material.

“ Some further methods

 

PRIVATE SECTION.

“ Some hidden methods

PROTECTED SECTION.

ENDCLASS.

 

CLASS zcl_material IMPLEMENTATION.

 

METHOD constructor.

“ Some very slow but unavoidable code

ENDMETHOD.

 

METHOD clone.

SYSTEM-CALL OBJMGR CLONE me TO ro_material.

ENDMETHOD.

 

“ Some more methods

ENDCLASS.

 

Normally, within the CLONE method, we would create the object RO_MATERIAL (avoiding the slow code in the constructor using flag variables and conditions) and copy the entire state of ME to RO_MATERIAL. However, we used a cheat code. What you see is a system call to clone ME, which is not meant for external use. No one gets hurt by little hacks like this, as long as the unit tests are done well.

 

Now, back to CL_PURCHASE. Instead of creating a new CL_MATERIAL object every time ADD_LINE is called, we will clone an existing material object whenever possible. The code to do so can be seen below.

 

METHOD add_line.

DATA lo_material TYPE REF TO zcl_material.

 

ASSIGN gt_line[ matnr = is_line-matnr ]

TO FIELD-SYMBOL(<ls_line>).

IF sy-subrc EQ 0.

lo_material = <ls_line>-obj_material->clone( ).

ELSE.

lo_material = NEW zcl_material( is_line-matnr ).

ENDIF.

 

APPEND VALUE #(

obj_material = lo_material

lifnr = is_line-lifnr

matnr = is_line-matnr

price = VALUE #(

preis = is_line-preis

waers = is_line-waers )

quan = VALUE #(

menge = is_line-menge

meins = is_line-meins )

) TO gt_line.

ENDMETHOD.

 

Conclusion

Brilliant, isn’t it? Instead of re-calling the constructor every time the same material is added, we simply cloned an existing object and avoided the initialization runtime cost. This trick to using prototype design patterns in your ABAP programs should save you quite a bit of time.

 

Editor’s note: This post has been adapted from a section of the book Design Patterns in ABAP Objects by Kerem Koseoglu.