Application Development Discussions
Join the discussions or start your own on all things application development, including tools and APIs, programming models, and keeping your skills sharp.
cancel
Showing results for 
Search instead for 
Did you mean: 

How to implement Strategy pattern in ABAP Objects?

Former Member
0 Kudos

Hello,

I have a problem where I need to implement different algorithms, depending on the type of input. Example: I have to calculate a Present Value, sometimes with payments in advance, sometimes payment in arrear.

From documentation and to enhance my ABAP Objects skills, I would like to implement the strategy pattern. It sounds the right solution for the problem.

Hence I need some help in implementing this pattern in OO. I have some basic OO skills, but still learning.

Has somebody already implemented this pattern in ABAP OO and can give me some input. Or is there any documentation how to implement it?

Thanks and regards,

Tapio

1 ACCEPTED SOLUTION

MarcinPciak
Active Contributor
0 Kudos

Keshav has already outlined required logic, so let me fulfill his answer with a snippet

An Interface


INTERFACE lif_payment.
  METHODS pay CHANGING c_val TYPE p.
ENDINTERFACE.

Payment implementations


CLASS lcl_payment_1 DEFINITION.
  PUBLIC SECTION.
  INTERFACES lif_payment.
  ALIASES pay for lif_payment~pay.
ENDCLASS.                  


CLASS lcl_payment_2 DEFINITION.
  PUBLIC SECTION.
  INTERFACES lif_payment.
  ALIASES pay for lif_payment~pay.
ENDCLASS.                    


CLASS lcl_payment_1 IMPLEMENTATION.
  METHOD pay.
    "do something with c_val i.e.
    c_val = c_val - 10.
  ENDMETHOD.                    
ENDCLASS.                   


CLASS lcl_payment_2 IMPLEMENTATION.
  METHOD pay.
    "do something else with c_val i.e.
    c_val = c_val + 10.
  ENDMETHOD.   

Main class which uses strategy pattern


CLASS lcl_main DEFINITION.
  PUBLIC SECTION.
    "during main object creation you pass which payment you want to use for this object
    METHODS constructor IMPORTING ir_payment TYPE REF TO lif_payment.
    "later on you can change this dynamicaly
    METHODS set_payment IMPORTING ir_payment TYPE REF TO lif_payment.
    METHODS show_payment_val.
    METHODS pay.

  PRIVATE SECTION.
    DATA payment_value TYPE p.
    "reference to your interface whcih you will be working with
    "polimorphically
    DATA mr_payment TYPE REF TO lif_payment.
ENDCLASS.                   

CLASS lcl_main IMPLEMENTATION.
  METHOD constructor.
    IF ir_payment IS BOUND.
      me->mr_payment = ir_payment.
    ENDIF.
  ENDMETHOD.                   
  METHOD set_payment.
    IF ir_payment IS BOUND.
      me->mr_payment = ir_payment.
    ENDIF.
  ENDMETHOD.                   
  METHOD show_payment_val.
    WRITE /: 'Payment value is now ', me->payment_value.
  ENDMETHOD.                   
  "hide fact that you are using composition to access pay method
  METHOD pay.
    mr_payment->pay( CHANGING c_val = payment_value ).
  ENDMETHOD.                   ENDCLASS.                   

Client application


PARAMETERS pa_pay TYPE c. "1 - first payment, 2 - second

DATA gr_main TYPE REF TO lcl_main.
DATA gr_payment TYPE REF TO lif_payment.

START-OF-SELECTION.
  "client application (which uses stategy pattern)

  CASE pa_pay.
    WHEN 1.
      "create first type of payment
      CREATE OBJECT gr_payment TYPE lcl_payment_1.
    WHEN 2.
      "create second type of payment
      CREATE OBJECT gr_payment TYPE lcl_payment_2.
  ENDCASE.
  "pass payment type to main object
  CREATE OBJECT gr_main
    EXPORTING
      ir_payment = gr_payment.

  gr_main->show_payment_val( ).
  "now client doesn't know which object it is working with
  gr_main->pay( ).

  gr_main->show_payment_val( ).

  "you can also use set_payment method to set payment type dynamically
  "client would see no change
  if pa_pay = 1.
    "now create different payment to set it dynamically
    CREATE OBJECT gr_payment TYPE lcl_payment_2.

    gr_main->set_payment( gr_payment ).
    gr_main->pay( ).
    gr_main->show_payment_val( ).
  endif.

Regads

Marcin

3 REPLIES 3

kesavadas_thekkillath
Active Contributor
0 Kudos

Hi,

I am not a high skilled OO ABAP guy but still i can give you some hints. You can design an interface which holds your method for calculation. Create classes for different algorithms and implement the interface in it.Create a reference to the interface and based on the type of input create the object and call the method ( generaly known as polymorphism ).

Guys I am just going through the desing pattern documents suggested by Marcin and if there is any mistake then correct me.

MarcinPciak
Active Contributor
0 Kudos

Keshav has already outlined required logic, so let me fulfill his answer with a snippet

An Interface


INTERFACE lif_payment.
  METHODS pay CHANGING c_val TYPE p.
ENDINTERFACE.

Payment implementations


CLASS lcl_payment_1 DEFINITION.
  PUBLIC SECTION.
  INTERFACES lif_payment.
  ALIASES pay for lif_payment~pay.
ENDCLASS.                  


CLASS lcl_payment_2 DEFINITION.
  PUBLIC SECTION.
  INTERFACES lif_payment.
  ALIASES pay for lif_payment~pay.
ENDCLASS.                    


CLASS lcl_payment_1 IMPLEMENTATION.
  METHOD pay.
    "do something with c_val i.e.
    c_val = c_val - 10.
  ENDMETHOD.                    
ENDCLASS.                   


CLASS lcl_payment_2 IMPLEMENTATION.
  METHOD pay.
    "do something else with c_val i.e.
    c_val = c_val + 10.
  ENDMETHOD.   

Main class which uses strategy pattern


CLASS lcl_main DEFINITION.
  PUBLIC SECTION.
    "during main object creation you pass which payment you want to use for this object
    METHODS constructor IMPORTING ir_payment TYPE REF TO lif_payment.
    "later on you can change this dynamicaly
    METHODS set_payment IMPORTING ir_payment TYPE REF TO lif_payment.
    METHODS show_payment_val.
    METHODS pay.

  PRIVATE SECTION.
    DATA payment_value TYPE p.
    "reference to your interface whcih you will be working with
    "polimorphically
    DATA mr_payment TYPE REF TO lif_payment.
ENDCLASS.                   

CLASS lcl_main IMPLEMENTATION.
  METHOD constructor.
    IF ir_payment IS BOUND.
      me->mr_payment = ir_payment.
    ENDIF.
  ENDMETHOD.                   
  METHOD set_payment.
    IF ir_payment IS BOUND.
      me->mr_payment = ir_payment.
    ENDIF.
  ENDMETHOD.                   
  METHOD show_payment_val.
    WRITE /: 'Payment value is now ', me->payment_value.
  ENDMETHOD.                   
  "hide fact that you are using composition to access pay method
  METHOD pay.
    mr_payment->pay( CHANGING c_val = payment_value ).
  ENDMETHOD.                   ENDCLASS.                   

Client application


PARAMETERS pa_pay TYPE c. "1 - first payment, 2 - second

DATA gr_main TYPE REF TO lcl_main.
DATA gr_payment TYPE REF TO lif_payment.

START-OF-SELECTION.
  "client application (which uses stategy pattern)

  CASE pa_pay.
    WHEN 1.
      "create first type of payment
      CREATE OBJECT gr_payment TYPE lcl_payment_1.
    WHEN 2.
      "create second type of payment
      CREATE OBJECT gr_payment TYPE lcl_payment_2.
  ENDCASE.
  "pass payment type to main object
  CREATE OBJECT gr_main
    EXPORTING
      ir_payment = gr_payment.

  gr_main->show_payment_val( ).
  "now client doesn't know which object it is working with
  gr_main->pay( ).

  gr_main->show_payment_val( ).

  "you can also use set_payment method to set payment type dynamically
  "client would see no change
  if pa_pay = 1.
    "now create different payment to set it dynamically
    CREATE OBJECT gr_payment TYPE lcl_payment_2.

    gr_main->set_payment( gr_payment ).
    gr_main->pay( ).
    gr_main->show_payment_val( ).
  endif.

Regads

Marcin

0 Kudos

Hi Marcin,

this was really helpful! Thanks a lot.

Best regards,

Tapio