In this blog, I want to show an example of one of the object-oriented principle Inversion of control. It is implemented in the TSW (Trader’s and Scheduler’s Workbench). The approach taken is not so object oriented but it resemble the Concepts of Inversion of control. This blog is not for in detail understanding of junctions in TSW.
Before digging to the example, let us first understand the principle.
Inversion of control Principle
This Object-oriented Principe dictates that high-level components should not depends on the low-level components and both depends on the same abstraction. This is the specialization of the principle depends on the abstraction, do not depend on the concrete classes. Inversion of control can be achieved by several mechanisms such as-
- Factory pattern
- Strategy Pattern
- Dependency Injection
But what does all that mean to us and why do we do that? Let me explain this with a simplistic example through Simple Factory Pattern and dependency injection in static method –
REPORT ZIOC_Test. INTERFACE document. METHODS: create_document, write_docuemnt, save_document. ENDINTERFACE. CLASS document_factory DEFINITION FINAL. PUBLIC SECTION. CLASS-METHODS get_document IMPORTING i_p_doc TYPE char2 RETURNING VALUE(r_result) TYPE REF TO document. ENDCLASS. CLASS purchase_order DEFINITION . PUBLIC SECTION. INTERFACES document. ENDCLASS. CLASS sales_order DEFINITION. PUBLIC SECTION. INTERFACES document. ENDCLASS. CLASS purchase_order IMPLEMENTATION. METHOD document~create_document. ENDMETHOD. METHOD document~save_document. ENDMETHOD. METHOD document~write_docuemnt. ENDMETHOD. ENDCLASS. CLASS sales_order IMPLEMENTATION. METHOD document~create_document. ENDMETHOD. METHOD document~save_document. ENDMETHOD. METHOD document~write_docuemnt. ENDMETHOD. ENDCLASS. CLASS document_factory IMPLEMENTATION. METHOD get_document. r_result = SWITCH #( i_p_doc WHEN 'PO' THEN NEW purchase_order( ) WHEN 'SO' THEN NEW sales_order( ) ). ENDMETHOD. ENDCLASS. SELECTION-SCREEN BEGIN OF BLOCK b1 WITH FRAME TITLE TEXT-001. PARAMETERS: p_doc TYPE char2. SELECTION-SCREEN END OF BLOCK b1. DATA lv_document TYPE REF TO document. START-OF-SELECTION. *-------------------------------- *! Without Inversion of control *-------------------------------- lv_document = SWITCH #( p_doc WHEN 'PO' THEN NEW purchase_order( ) WHEN 'SO' THEN NEW sales_order( ) ). lv_document->create_document( ). lv_document->write_docuemnt( ). lv_document->save_document( ). *-------------------------------- *! With Inversion of control *-------------------------------- lv_document = document_factory=>get_document( p_doc ). lv_document->create_document( ). lv_document->write_docuemnt( ). lv_document->save_document( ).
In the above example, I have created one document interfaces and two document classes Purchase_Order and Sales_Order which uses the document interface. In start-of-selection event there are two approach to create the instance of the document classes based on the selection screen parameter.
The first Approach is without inversion of control. In this approach our main program (Report Program) is directly dependent on the instantiation of the concrete classes. As the changes in software are inevitable, changing in the instantiation logic lead to change the main program which is never our intention and doing so shall create a risk of breaking the program unintentionally. This also implies that the high level module (Main Program) is dependent on the low level module (Purchase Order and Sales Order concrete classes).
In the later approach, I have created a factory class to get the instance of the Purchase Order or Sales order by passing the dependency as an importing parameter. In this case the main program is dependent on the abstract document which will be returned by the factory and the concrete implementation is also depends on the abstract document, Hence the low level module (Concrete classes) doesn’t depend on the high level module (Main Program) but both depends on the abstraction (document interface).
Moving on to SAP example-
Inversion of control in TSW Junctions
To use TSW Junction function following steps need to be followed, before creating any program-
- Create Junction
- Create Application group under the Junctions
- Create Function Modules under the Application groups
- Assign Function Modules to Application Group
Now we write the programs by providing the Junction name and Application group as dependency. And all the function modules are configured under the Application group. Till the run time, the main program does not know which function module it has to execute; it depends on what is configured.
In such way our high level module (main program) depends on the Junctions which we pass as dependencies from our main program and low level module (Function Modules) also depends on the junctions. so Junctions are the abstract layer of the overall process.
The advantage of above architecture are:
- Decoupling of the execution of task from its implementation.
- Greater level of modularization.
- Easier to switch between implementation.
- Easy to add new functionality in the form of function modules.
By using Inversion of control and dependency injections one can create highly maintainable programs by decoupling the dependencies among the objects.
The software framework also uses Inversion of control principle. Frameworks takes control of the flow of the program and run our business logic. For e.g. BOPF framework, it uses dependency injection (BO key) to get the instance of the service manager. which is a form of constructor injection.
Hope the content is informative. Please do comment your thoughts!!