Additional Blogs by Members
cancel
Showing results for 
Search instead for 
Did you mean: 
Former Member
0 Kudos

Factory Pattern with Singleton Pattern

I will share with you how am using the factory and singleton pattern.

I found it more useful to use singleton pattern and factory pattern together. The factory pattern will control which instance of an object are single instances and which not.

How the code works:

  1. The program requests the factory class for an object, supplying the object name.
  2. The factory class check in the internal table l_tbl_objects if an instance of the object with the same name is already created.
  3. If the object exists in the internal the system return the instance of that object.
  4. If the object does not exists the system creates a new instance of the object and stores it into the l_tbl_objects table.

For creating singleton objects we will store the instance of the object in an internal table (we assume a single object exist within a user session):

begin of L_SC_OBJECTS,
object_name type string,
object type REF TO Z_OBJECT,
end of L_SC_OBJECTS.

Data: l_tbl_objects type STANDARD TABLE of L_SC_OBJECTS.

The factory class would be a static object:

CLASS z_factory DEFINITION.
PUBLIC SECTION.
CLASS-METHODS:
get_counter
IMPORTING
i_v_counter_type
TYPE string
RETURNING
value(r_v_object) TYPE REF TO object

.
PRIVATE SECTION.
CLASS-DATA:
l_tbl_objects
TYPE STANDARD TABLE OF  l_sc_objects.
CLASS-METHODS:
_createobject
IMPORTING
i_v_class
TYPE STRING
RETURNING
value(r_o_object) TYPE REF TO object,
_objectexists
IMPORTING
i_v_objectname
TYPE string
RETURNING
value(r_v_exist) TYPE i,
_object
IMPORTING
i_v_objectname
TYPE string
RETURNING
value(r_v_object) TYPE ref to object ,
_add_object
IMPORTING
i_O_object
TYPE REF TO object
i_v_objectname
TYPE string
.

ENDCLASS.                    "z_factory DEFINITION

For creating objects dynamically you use (code I borrow from CL_EXITHANDLER)

CONCATENATE  '\CLASS=' i_v_class INTO l_v_classname.
CREATE OBJECT l_o_object TYPE (l_v_classname).

However in the example below the object is a local class therefore we need to include the Program name ahead of the  the \class

CONCATENATE  '\PROGRAM=!MY_TEST1\CLASS=' i_v_class INTO l_v_classname.

The factory implementation

LASS z_factory IMPLEMENTATION.
METHOD get_counter.
DATA: l_v_objectname TYPE string,
l_o_counter
TYPE REF TO object,
l_v_return
TYPE i,
l_o_obj
TYPE REF TO object
.

MOVE i_v_counter_type TO l_v_objectname .

CALL METHOD z_factory=>_objectexists
EXPORTING
i_v_objectname
= l_v_objectname
RECEIVING
r_v_exist     
= l_v_return.

IF l_v_return  EQ 0.
CALL METHOD z_factory=>_object
EXPORTING
i_v_objectname
= l_v_objectname
RECEIVING
r_v_object    
= l_o_obj.
MOVE l_o_obj ?TO r_v_object.
RETURN.
ENDIF.

"CREATE OBJECT l_o_counter.
l_o_counter ?= z_factory
=>_createobject( i_v_class = 'Z_COUNTER' ).
MOVE  l_o_counter TO  l_o_obj.

CALL METHOD z_factory=>_add_object
EXPORTING
i_o_object    
= l_o_obj
i_v_objectname
= l_v_objectname.


r_v_object
= l_o_counter.

ENDMETHOD.                    "Get_Counter

METHOD _createobject.
DATA: l_o_object TYPE REF TO object,
l_v_classname
TYPE string
.

CONCATENATE  '\PROGRAM=!CH_TEST1\CLASS=' i_v_class INTO l_v_classname.

CREATE OBJECT l_o_object TYPE (l_v_classname).

MOVE l_o_object TO r_o_object.
ENDMETHOD.                    "_createobject

METHOD _objectexists.


READ TABLE l_tbl_objects WITH KEY object_name = i_v_objectname TRANSPORTING NO FIELDS.

IF sy-subrc EQ 0.
r_v_exist
= 0.
ELSE.
r_v_exist
-1.
ENDIF.

ENDMETHOD.                    "_OBJECTEXISTS

METHOD _object.
DATA: l_wa_objects TYPE l_sc_objects.

READ TABLE l_tbl_objects WITH KEY object_name = i_v_objectname
INTO l_wa_objects.

IF sy-subrc EQ 0.
MOVE l_wa_objects-object TO r_v_object.
ENDIF.


ENDMETHOD.                    "_OBJECT

METHOD _add_object.
DATA: l_wa_cast TYPE l_sc_objects.

FIELD-SYMBOLS: <f_sec> TYPE  l_sc_objects.

l_wa_cast
-object_name = i_v_objectname.
l_wa_cast
-object = i_o_object.

READ TABLE l_tbl_objects  ASSIGNING <f_sec>  WITH KEY object_name = l_wa_cast-object_name.

IF sy-subrc EQ 0.
<f_sec>
-object = i_o_object.
ELSE.
APPEND l_wa_cast TO l_tbl_objects.
ENDIF.
ENDMETHOD.                    "_add_object

ENDCLASS.                    "z_Factory IMPLEMENTATION

Test scenario

We create a test object

CLASS z_counter DEFINITION.
PUBLIC SECTION.
METHODS:
contructor
,
add_value
,
counter
RETURNING
value(r_v_amount) TYPE i.
PRIVATE SECTION.
DATA: l_v_amount TYPE i.
ENDCLASS.                    "z_COUNTER DEFINITION

*----------------------------------------------------------------------*
*       CLASS z_COUNTER IMPLEMENTATION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS z_counter IMPLEMENTATION.
METHOD  contructor.
l_v_amount
= 0.
ENDMETHOD.                    "CONTRUCTOR
METHOD add_value.
l_v_amount
= l_v_amount + 1.
ENDMETHOD.                    "ADD_VALUE
METHOD  counter.
r_v_amount
= l_v_amount.
ENDMETHOD.                    "COUNTER
ENDCLASS.                    "z_COUNTER IMPLEMENTATION

Define 2 instances of the object

DATA:
l_o_counter1
TYPE REF TO   z_counter    ,
l_o_counter2
TYPE REF TO   z_counter ,
l_v_i
TYPE i ,
l_v_i2
TYPE i
.

Create the objects

l_o_counter1 ?= z_factory=>get_counter('CARS').
l_v_i
= l_o_counter1->counter( ).
l_o_counter2 ?= z_factory
=>get_counter('CARS').
l_o_counter2
->add_value( ).
l_o_counter2
->add_value( ).


WRITE l_v_i.
l_v_i
= l_o_counter1->counter( ).
l_v_i2
= l_o_counter2->counter( ).
WRITE: l_v_i, l_v_i2.