Implementing Factory Methods

Objectives

After completing this lesson, you will be able to:

  • Use factory methods

Factory Methods

Sometimes a class needs to keep control of its instances. This could be to prevent multiple instances being created. In order to do so, it must prevent its users from creating instances themselves. You do this in ABAP by using the CREATE PRIVATE addition in the CLASS DEFINITION statement. Any attempt to use the NEW operator outside the class will now lead to a syntax error. Note that other programming languages achieve this effect by altering the visibility of the constructor method. ABAP does not support this.

Since users of the class cannot create their own instances, the class must then provide a public static method that creates instances and returns them to the user. This is called a factory method.

Try It Out: Factory Methods Implementation

  1. Create a new class that implements the interface IF_OO_ADT_CLASSRUN.
  2. Switch to the Local Types tab and copy the following code snippet into the editor:
    Code snippet
    
    CLASS lcl_connection DEFINITION CREATE PRIVATE.
    PUBLIC SECTION.
    METHODS constructor
    IMPORTING
    airlineid TYPE /dmo/carrier_id
    connectionnumber TYPE /dmo/connection_id
    fromAirport TYPE /dmo/airport_from_id
    toAirport TYPE /dmo/airport_to_id.
    
    
    CLASS-METHODS get_connection IMPORTING airlineId TYPE /dmo/carrier_id
    connectionNumber TYPE /dmo/connection_id
    RETURNING VALUE(ro_connection) TYPE REF TO lcl_Connection.
    
    
    PRIVATE SECTION.
    DATA AirlineId TYPE /dmo/carrier_id.
    DATA ConnectionNumber TYPE /dmo/connection_id.
    DATA fromAirport TYPE /dmo/airport_from_id.
    DATA toAirport TYPE /dmo/airport_to_id.
    ENDCLASS.
    
    CLASS lcl_connection IMPLEMENTATION.
    
    METHOD constructor.
    
    
    me->airlineid = airlineid.
    me->connectionnumber = connectionnumber.
    me->fromAirport = fromAirport.
    me->toAirport = toAirport.
    
    
    ENDMETHOD.
    
    
    METHOD get_connection.
    DATA fromAirport TYPE /dmo/airport_from_id.
    DATA toAirport TYPE /dmo/airport_to_id.
    
    
    SELECT SINGLE FROM /dmo/connection FIELDS airport_from_id, airport_to_id
    WHERE carrier_id = @airlineid
    AND connection_id = @connectionnumber
    INTO ( @fromAirport, @toAirport ).
    
    
    ro_connection = NEW #( airlineid = airlineid connectionnumber = connectionnumber fromairport = fromairport toairport = toairport ).
    
    
    ENDMETHOD.
    
    
    ENDCLASS.
    Expand
  3. Switch to the Global Class tab and paste the following code snippet into the implementation of method if_oo_adt_classrun~main( ):
    Code snippet
    
    CLASS zcl_s4d401_factory DEFINITION
    PUBLIC
    FINAL
    CREATE PUBLIC .
    
    
    PUBLIC SECTION.
    interfaces if_oo_adt_classrun.
    PROTECTED SECTION.
    PRIVATE SECTION.
    ENDCLASS.
    
    
    CLASS zcl_s4d401_factory IMPLEMENTATION.
    
    METHOD if_oo_adt_classrun~main.
    data connection type ref to lcl_connection.
    
    
    * Debug the method to show that the class returns objects, but that there are different
    * objects for the same combination of airline and flight number
    
    
    connection = lcl_connection=>get_connection( airlineid = 'LH' connectionnumber = '0400' ).
    
    
    connection = lcl_connection=>get_connection( airlineid = 'LH' connectionnumber = '0400' ).
    
    
    ENDMETHOD.
    
    
    ENDCLASS.
    Expand
  4. Activate the class with Ctrl + F3.
  5. Play around with the coding. In particular, debug the main() method and note the internal instance numbers assigned to the objects returned by the factory method.

Singleton Pattern Implementation

The purpose of the singleton pattern is to ensure that there is only one instance of a class in an application. This could be a single instance of the class or, in our case, a single instance for each combination of key attributes.

Try It Out: Singleton Pattern Implementation

  1. Create a new class that implements the interface IF_OO_ADT_CLASSRUN.
  2. Switch to the Local Types tab and copy the following code snippet into the editor:
    Code snippet
    
    CLASS lcl_connection DEFINITION CREATE PRIVATE.
    PUBLIC SECTION.
    METHODS constructor
    IMPORTING
    airlineid TYPE /dmo/carrier_id
    connectionnumber TYPE /dmo/connection_id
    fromAirport TYPE /dmo/airport_from_id
    toAirport TYPE /dmo/airport_to_id.
    
    
    CLASS-METHODS get_connection IMPORTING airlineId TYPE /dmo/carrier_id
    connectionNumber TYPE /dmo/connection_id
    RETURNING VALUE(ro_connection) TYPE REF TO lcl_Connection.
    
    PRIVATE SECTION.
    
    
    TYPES: BEGIN OF ts_instance,
    airlineId TYPE /dmo/carrier_id,
    connectionNumber TYPE /dmo/connection_id,
    object TYPE REF TO lcl_connection,
    END OF ts_instance,
    tt_instances TYPE HASHED TABLE OF ts_instance
    WITH UNIQUE KEY airlineId ConnectionNumber.
    
    
    DATA AirlineId TYPE /dmo/carrier_id.
    DATA ConnectionNumber TYPE /dmo/connection_id.
    DATA fromAirport TYPE /dmo/airport_from_id.
    DATA toAirport TYPE /dmo/airport_to_id.
    CLASS-DATA connections TYPE tt_instances.
    ENDCLASS.
    
    
    CLASS lcl_connection IMPLEMENTATION.
    
    
    METHOD constructor.
    
    
    me->airlineid = airlineid.
    me->connectionnumber = connectionnumber.
    me->fromAirport = fromAirport.
    me->toAirport = toAirport.
    
    
    ENDMETHOD.
    
    
    METHOD get_connection.
    DATA fromAirport TYPE /dmo/airport_from_id.
    DATA toAirport TYPE /dmo/airport_to_id.
    
    
    IF NOT line_exists( connections[ airlineid = airlineid connectionnumber = connectionnumber ] ).
    SELECT SINGLE FROM /dmo/connection FIELDS airport_from_id, airport_to_id
    WHERE carrier_id = @airlineid
    AND connection_id = @connectionnumber
    INTO ( @fromAirport, @toAirport ).
    
    
    ro_connection = NEW #( airlineid = airlineid connectionnumber = connectionnumber fromairport = fromairport toairport = toairport ).
    DATA(new_instance) = VALUE ts_instance( airlineId = airlineId connectionnumber = connectionnumber object = ro_connection ).
    INSERT new_instance INTO TABLE connections.
    ELSE.
    ro_connection = connections[ airlineId = airlineId connectionnumber = connectionnumber ]-object.
    ENDIF.
    
    
    ENDMETHOD.
    
    
    ENDCLASS.
    Expand
  3. Switch to the Global Class tab and paste the following code snippet into the implementation of method if_oo_adt_classrun~main( ):
    Code snippet
    
    CLASS zcl_s4d401_factory_singleton DEFINITION
    PUBLIC
    FINAL
    CREATE PUBLIC .
    
    
    PUBLIC SECTION.
    interfaces if_oo_adt_classrun.
    PROTECTED SECTION.
    PRIVATE SECTION.
    ENDCLASS.
    
    CLASS zcl_s4d401_factory_singleton IMPLEMENTATION.
    
    METHOD if_oo_adt_classrun~main.
    data connection type ref to lcl_connection.
    
    
    * Debug the method to show that the class always returns the same object
    * for the same combination of airline and flight number
    
    
    connection = lcl_connection=>get_connection( airlineid = 'LH' connectionnumber = '0400' ).
    
    
    connection = lcl_connection=>get_connection( airlineid = 'LH' connectionnumber = '0400' ).
    
    
    ENDMETHOD.
    
    
    ENDCLASS.
    Expand
  4. Activate the class with Ctrl + F3.
  5. Play around with the coding. In particular, debug the main() method and note the internal instance numbers assigned to the objects returned by the factory method.

Log in to track your progress & complete quizzes