22/11/2010

Dependency Injection in ABAP OO

Introduction

Dependency Injection (DI) is a technique and a set of design patterns that enable us to develop loosely coupled code. Instead of directly instantiating concrete classes whenever we need to invoke a particular service, we program against interfaces. Instances of these interfaces are injected into the code by the external client so that the code can vary independently of the Dependency.

Here we will take a detailed look at the DI pattern known as Constructor Injection. Since it is a design pattern, I have chosen to present it in the formal design pattern style.

How do we guarantee that a necessary Dependency is always available to the class we are currently developing?

By requiring all callers to supply the Dependency as a parameter to the class' constructor.


REPORT ZADN_SAMPLE.

*----------------------------------------------------------------------*
* -> INTERFACE IF_LOG_PERSISTENCE
*----------------------------------------------------------------------*
INTERFACE if_log_persistence.

METHODS : save_log IMPORTING p_message TYPE char128.

ENDINTERFACE. "IF_LOG_PERSISTENCE

*----------------------------------------------------------------------*
* -> CLASS lc_log_in_email DEFINITION
*----------------------------------------------------------------------*
CLASS lc_log_in_email DEFINITION.

PUBLIC SECTION.

INTERFACES : if_log_persistence.

ENDCLASS. "lc_log_in_email DEFINITION

*----------------------------------------------------------------------*
* -> CLASS lc_log_in_email IMPLEMENTATION
*----------------------------------------------------------------------*
CLASS lc_log_in_email IMPLEMENTATION.

METHOD if_log_persistence~save_log.

WRITE / : 'LOG SEND BY EMAIL',
'-----------------',
p_message.

ENDMETHOD. "if_log_persistence~save_log

ENDCLASS. "lc_log_in_email IMPLEMENTATION

*----------------------------------------------------------------------*
* -> CLASS lc_log_in_file DEFINITION
*----------------------------------------------------------------------*
CLASS lc_log_in_file DEFINITION.

PUBLIC SECTION.

INTERFACES : if_log_persistence.

ENDCLASS. "lc_log_in_file DEFINITION

*----------------------------------------------------------------------*
* -> CLASS lc_log_in_file IMPLEMENTATION
*----------------------------------------------------------------------*
CLASS lc_log_in_file IMPLEMENTATION.

METHOD if_log_persistence~save_log.

WRITE / : 'LOG SEND TO FILE',
'-----------------',
p_message.

ENDMETHOD. "if_log_persistence~save_log

ENDCLASS. "lc_log_in_file IMPLEMENTATION

*----------------------------------------------------------------------*
* -> CLASS lc_log_in_database DEFINITION
*----------------------------------------------------------------------*
CLASS lc_log_in_database DEFINITION.

PUBLIC SECTION.

INTERFACES : if_log_persistence.

ENDCLASS. "lc_log_in_database DEFINITION

*----------------------------------------------------------------------*
* -> CLASS lc_log_in_database IMPLEMENTATION
*----------------------------------------------------------------------*
CLASS lc_log_in_database IMPLEMENTATION.

METHOD if_log_persistence~save_log.

WRITE / : 'LOG CREATE IN DATABASE TABLE',
'-----------------',
p_message.

ENDMETHOD. "if_log_persistence~save_log

ENDCLASS. "lc_log_in_database IMPLEMENTATION

*----------------------------------------------------------------------*
* -> CLASS LC_CALCULATOR DEFINITION
*----------------------------------------------------------------------*
CLASS lc_calculator DEFINITION.

PUBLIC SECTION.

METHODS : constructor IMPORTING p_log_target TYPE REF TO if_log_persistence,
div IMPORTING p_x TYPE i p_y TYPE i.

PRIVATE SECTION.

DATA : v_value TYPE i,
v_msg TYPE char128,
o_log TYPE REF TO if_log_persistence,
o_exp TYPE REF TO cx_sy_zerodivide.

ENDCLASS. "LC_CALCULATOR DEFINITION

*----------------------------------------------------------------------*
* -> CLASS LC_CALCULATOR IMPLEMENTATION
*----------------------------------------------------------------------*
CLASS lc_calculator IMPLEMENTATION.

METHOD constructor.

me->o_log = p_log_target.

ENDMETHOD. "CONSTRUCTOR

METHOD div.

TRY.

me->v_value = ( p_x / p_y ).

WRITE / : ' Division Operation = ', me->v_value.

CATCH cx_sy_zerodivide INTO me->o_exp.

me->v_msg = o_exp->get_text( ).

o_log->save_log( me->v_msg ).

ENDTRY.

ENDMETHOD. "DIV

ENDCLASS. "LC_CALCULATOR IMPLEMENTATION

************************************************************************
************************************************************************
* *
* PROGRAM FLOW LOGIC *
* *
************************************************************************

*----------------------------------------------------------------------*
* -> DEFINE SCREEN ELEMENTS
*----------------------------------------------------------------------*
PARAMETERS : p_ltype TYPE i DEFAULT 1. " Use 1, 2, 3 or 4
" with value of p_ltype

*----------------------------------------------------------------------*
* -> START-OF-SELECTION EVENT PROCESSING
*----------------------------------------------------------------------*
START-OF-SELECTION.

DATA : o_log_in_database TYPE REF TO lc_log_in_database,
o_log_in_file TYPE REF TO lc_log_in_file,
o_log_in_email TYPE REF TO lc_log_in_email,
o_calculator TYPE REF TO lc_calculator.

CASE p_ltype.

WHEN 1.

CREATE OBJECT o_log_in_database.

IF o_log_in_database IS BOUND.

CREATE OBJECT o_calculator
EXPORTING
p_log_target = o_log_in_database.

IF o_calculator IS BOUND.

o_calculator->div( EXPORTING p_x = 1 p_y = 1 ). " Sucess
o_calculator->div( EXPORTING p_x = 1 p_y = 0 ). " Error

ENDIF.

ENDIF.

WHEN 2.

CREATE OBJECT o_log_in_file.

IF o_log_in_file IS BOUND.

CREATE OBJECT o_calculator
EXPORTING
p_log_target = o_log_in_file.

o_calculator->div( EXPORTING p_x = 2 p_y = 1 ). " Sucess
o_calculator->div( EXPORTING p_x = 2 p_y = 0 ). " Error

ENDIF.

WHEN 3.

CREATE OBJECT o_log_in_email.

IF o_log_in_email IS BOUND.

CREATE OBJECT o_calculator
EXPORTING
p_log_target = o_log_in_email.

o_calculator->div( EXPORTING p_x = 3 p_y = 1 ). " Sucess
o_calculator->div( EXPORTING p_x = 3 p_y = 0 ). " Error

ENDIF.

WHEN OTHERS.

WRITE / 'NO IMPLEMENTATION ACTIVE FOR THIS LOG TYPE'.

ENDCASE.

Um comentário:

  1. We started implementing dependency injetion in ABAP. First usable piece of software is available at
    http://code.google.com/p/abap-di/

    ResponderExcluir