I have a task to create a simple demo of the multition design pattern in ABAP.
As far as I understand instances created should be stored into a static internal table so they can later be used. Here is my attempt:
CLASS zrp_casino_bl DEFINITION
PUBLIC
FINAL
CREATE PRIVATE .
PUBLIC SECTION.
CLASS-METHODS: get_instance IMPORTING i_player_id TYPE i OPTIONAL"Here i_player_id - key for creating the instance. Assume that duplicate names cannot exist.
"Optional, so that the user has the option to create a new instance or call and existing one via the key
RETURNING VALUE(r_instance) TYPE REF TO zrp_casino_bl.
METHODS: print_player_info.
PROTECTED SECTION.
PRIVATE SECTION.
TYPES: BEGIN OF player_info_st,
player_id TYPE i,
instance TYPE REF TO zrp_casino_bl,
END OF player_info_st,
player_info_tt TYPE TABLE OF player_info_st WITH DEFAULT KEY.
CLASS-DATA: player_info_tab TYPE player_info_tt,
player_id TYPE i,
player_winnings TYPE i,
win_or_loose TYPE abap_bool.
DATA: instance_data TYPE REF TO zrp_casino_bl.
METHODS: assign_winnings RETURNING VALUE(r_winnings) TYPE i,
determine_win_or_loose RETURNING VALUE(r_result) TYPE abap_bool,
constructor IMPORTING i_player_id TYPE i OPTIONAL.
CLASS-METHODS: get_max_player_id RETURNING VALUE(r_maxid) TYPE i,
add_new_instance IMPORTING i_player_id TYPE i OPTIONAL
RETURNING VALUE(r_instance) TYPE REF TO zrp_casino_bl,
retrieve_existing_instance IMPORTING i_player_id TYPE i
RETURNING VALUE(r_instance) TYPE REF TO zrp_casino_bl.
ENDCLASS.
CLASS zrp_casino_bl IMPLEMENTATION.
METHOD determine_win_or_loose.
"some simple stuff here, not important
METHOD assign_winnings.
IF player_id = 1.
r_winnings = 100.
ELSEIF player_id = 2.
r_winnings = 200.
ELSEIF player_id = 3.
r_winnings = 300.
ELSEIF player_id = 4.
r_winnings = -400.
ENDIF.
ENDMETHOD.
METHOD get_max_player_id.
SORT player_info_tab BY player_id DESCENDING.
r_maxid = player_info_tab[ 1 ]-player_id.
ENDMETHOD.
METHOD get_instance.
IF i_player_id IS NOT SUPPLIED.
r_instance = add_new_instance( ).
ELSE.
IF line_exists( player_info_tab[ player_id = i_player_id ] ).
r_instance = retrieve_existing_instance( i_player_id ).
ELSE.
r_instance = add_new_instance( i_player_id ).
ENDIF.
ENDIF.
ENDMETHOD.
METHOD constructor.
player_id = i_player_id.
player_winnings = me->assign_winnings( ).
win_or_loose = me->determine_win_or_loose( ).
ENDMETHOD.
METHOD print_player_info.
cl_demo_output=>display( 'Player name: ' && player_id && |\n| &&
'Player winnings: ' && player_winnings && |\n| &&
'Is the player winning : ' && win_or_loose ).
ENDMETHOD.
METHOD add_new_instance.
IF i_player_id IS SUPPLIED.
r_instance = NEW #( i_player_id ).
INSERT VALUE #( player_id = i_player_id instance = r_instance ) INTO TABLE player_info_tab.
ELSE.
r_instance = NEW #( get_max_player_id( ) + 1 ).
INSERT VALUE #( player_id = get_max_player_id( ) + 1 instance = r_instance ) INTO TABLE player_info_tab.
ENDIF.
ENDMETHOD.
METHOD retrieve_existing_instance.
LOOP AT player_info_tab ASSIGNING FIELD-SYMBOL(<info>) WHERE player_id = i_player_id.
r_instance = <info>-instance.
ENDLOOP.
ENDMETHOD.
ENDCLASS.
The results: Every time I create a new instance like this:
DATA(instance1) = zrp_casino_bl=>get_instance( i_player_id = 1 ).
instance1->print_player_info( ).
DATA(instance2) = zrp_casino_bl=>get_instance( i_player_id = 2 ).
instance2->print_player_info( ).
the instance gets saved to the table, but overwrites previously existing records. So this way if I create an instance with player id 1, 2, 3, 4 I will have 4 instance references in the table, but they will all refer to the lastly created instance.
I understand the issue - i'm using the NEW keyword, that overwrites existing records. How can I work around this? Any help will be greatly appreciated.
The problem is here:
This defines the data as static class data, which means the actual values of these variables are shared among all instances of the class. You have to declare these variable as instance variables (except the player_info_tab):