Summary: in this tutorial, you will learn how to implement the ABAP strategy design pattern with a practical example.
Problem
Sometimes when you enhance a report, a class, or an include, you have to pay a lot of effort and time to do regression tests in SAP.
There is a case that when you change one part, other parts are broken. Oop! To avoid such situations, the application should be designed to follow a dominant object-oriented design known as the open-closed principle.
The program should be designed in the way that it is open for extension and closed for modification to eliminate the impact on existing logic. In the design pattern, you use the strategy pattern to design the application to follow this open-closed principle.
Intent
Define a family of algorithms, encapsulate each one, and make them interchangeable. The strategy pattern lets the algorithm vary independently from clients that use it.
Strategy Design Pattern UML Diagram
The classes and/or objects are participating in the strategy design pattern are:
- Strategy
- The strategy interface defines methods that represent common algorithms. The context uses the strategy interface to call the algorithms implemented by ConcreteStrategy.
- ConcreteStrategy
- implements the algorithm defined in the strategy interface.
- Context
- Context object contains a reference to a Strategy object. The context object delegates requests from the client to the strategy object.
ABAP Strategy Design Pattern Implementation
In ABAP programming, you often have to create an interface between the SAP system and non-SAP systems.
One of the most common uses interfaces is File. You can extract data from SAP to files in CSV or tab-delimited format. The file then can be downloaded into the local computer or put it to the file server for further processing by the non-SAP system.
We can use strategy design pattern to design our program as UML below:
Explanation of interfaces and classes in the diagram above:
IF_EXTRACTABLE
is equivalent to StrategyCLI_FILE_CLIENT
,CL_FILE_SERVER
are equivalent to ConcreteStrategyCL_APP
is equivalent to Context
Suppose in the future you have a new requirement to send the file via email to a distribution list, you just have to create another class called CL_FILE_EMAIL that implements the interface IF_EXTRACTABLE
. Nothing needs to change except the logic handle email in the client. This is called the open-closed principle in object-oriented design.
The Strategy design pattern supports “open for extension” but “closed for modification”. All the code for handling file extract to local computer and server are unchanged and therefore eliminating the effort for regression test on these parts.
Let’s take a look a the ABAP code implementation.
The Interface IF_EXTRACTABLE
contains only one method called extract
:
*----------------------------------------------------------------------*
* INTERFACE if_extractable
*----------------------------------------------------------------------*
* ~ Strategy
*----------------------------------------------------------------------*
INTERFACE if_extractable.
METHODS:
extract.
ENDINTERFACE. "if_extractable
The CL_FILE_CLIENT
and CL_FILE_SERVER
classes implements IF_EXTRACTABLE
interface:
*----------------------------------------------------------------------*
* CLASS cl_file_client DEFINITION
*----------------------------------------------------------------------*
* ~ConcreteStrategy
*----------------------------------------------------------------------*
CLASS cl_file_client DEFINITION.
PUBLIC SECTION.
INTERFACES:
if_extractable.
ALIASES:
extract FOR if_extractable~extract.
ENDCLASS. "cl_file_client DEFINITION
*----------------------------------------------------------------------*
* CLASS cl_file_client IMPLEMENTATION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS cl_file_client IMPLEMENTATION.
METHOD extract.
WRITE: 'Save file to the local PC'.
ENDMETHOD. "extract
ENDCLASS. "cl_file_client IMPLEMENTATION
*----------------------------------------------------------------------*
* CLASS cl_file_server DEFINITION
*----------------------------------------------------------------------*
* ~ConcreteStrategy
*----------------------------------------------------------------------*
CLASS cl_file_server DEFINITION.
PUBLIC SECTION.
INTERFACES:
if_extractable.
ALIASES:
extract FOR if_extractable~extract.
ENDCLASS. "cl_file_server DEFINITION
*----------------------------------------------------------------------*
* CLASS cl_file_server IMPLEMENTATION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS cl_file_server IMPLEMENTATION.
METHOD extract.
WRITE: 'Save file to the server'.
ENDMETHOD. "extract
ENDCLASS. "cl_file_server IMPLEMENTATION
Next, implement Context class:
*----------------------------------------------------------------------*
* CLASS cl_app DEFINITION
*----------------------------------------------------------------------*
* ~Context
*----------------------------------------------------------------------*
CLASS cl_app DEFINITION.
PUBLIC SECTION.
METHODS:
constructor
IMPORTING im_extractable
TYPE REF TO if_extractable,
process_output.
PRIVATE SECTION.
DATA:
mo_extractable TYPE REF TO if_extractable.
ENDCLASS. "cl_app DEFINITION
*----------------------------------------------------------------------*
* CLASS cl_app IMPLEMENTATION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS cl_app IMPLEMENTATION.
METHOD constructor.
mo_extractable = im_extractable.
ENDMETHOD. "constructor
METHOD process_output.
IF mo_extractable IS NOT INITIAL.
mo_extractable->extract( ).
ENDIF.
ENDMETHOD. "process_output
ENDCLASS. "cl_app IMPLEMENTATION
Finally, develop a program to test our classes:
SELECTION-SCREEN BEGIN OF BLOCK b1 WITH FRAME TITLE text-001.
PARAMETERS: pa_local TYPE c RADIOBUTTON GROUP pout,
pa_servr TYPE c RADIOBUTTON GROUP pout.
SELECTION-SCREEN END OF BLOCK b1.
DATA:
go_app TYPE REF TO cl_app,
go_extract TYPE REF TO if_extractable.
START-OF-SELECTION.
CASE 'X'.
WHEN pa_local.
CREATE OBJECT go_extract TYPE cl_file_client.
WHEN pa_servr.
CREATE OBJECT go_extract TYPE cl_file_server.
ENDCASE.
CREATE OBJECT go_app
EXPORTING
im_extractable = go_extract.
go_app->process_output( ).
In this tutorial, you’ve learned how to implement the ABAP strategy design pattern that allows you to define a family of related algorithms, encapsulate each individual one, and make them interchangeable in terms of client uses.