ABAP Keyword Documentation → ABAP Programming Guidelines → ABAP-Specific Rules
ABAP Objects as a Programming Model
Other versions: 7.31 | 7.40 | 7.54
Background
ABAP is a hybrid programming language that supports both a procedural and an object-oriented programming model. The procedural programming model is based on the modularization of programs in classical processing blocks (event blocks, dialog modules, function modules and subroutines). In ABAP Objects, the class conceptually supersedes the classical program, and modularization is implemented using methods. From a technical point of view, classes are still declared and implemented in programs.
Both models possess interoperability, meaning that classes can be accessed in classical processing blocks and classical programs and procedures can be called within methods. The hybrid nature of the language is mainly due to the downward compatibility. This is because ABAP has procedural roots, and the introduction of the object-oriented programming model was intended to make sure entire programs and reusable procedures (primarily function modules) could still be used.
Rule
Use ABAP objects
Use ABAP objects wherever possible for new and further developments. Classical processing blocks should only be created in exceptional cases.
Details
The need to achieve separation of concerns is best supported by using ABAP objects as much as possible. Object-oriented programming - particularly ABAP Objects in comparison to classical procedural ABAP - is better suited. Here are the reasons why:
ABAP Objects enables an advanced type of data encapsulation to be used. In classical procedural programming, the state of an application is determined by the content of the global variables of a program. In object-oriented programming, the state is encapsulated in classes or objects as instances of classes. The distribution of data across the different visibility sections of a class — public, protected and private — allows a clear differentiation between externally and internally usable data. Even without in-depth object-oriented modeling, application programs benefit from these properties in terms of stability and maintainability.
ABAP Objects enables multiple instantiation of a class, by using explicit object creation with the
CREATE OBJECT
statement.
Each instance of a class (object) has its own state that is determined using the values of its attributes.
It can be changed using class methods. Automatic garbage collection ensures that any objects no longer
required are deleted from the memory. Procedural models do not offer multiple instantiation. Therefore stateless functions must be applied to data stored in separate repositories.
ABAP Objects enables the reuse of classes through inheritance, where classes with special behaviors are derived from more general classes. Only the differences must be implemented again. In the procedural model, only existing functions can be used as they are, or new functions must be created.
In ABAP Objects, objects can be addressed using standalone interfaces. This means that developers do not need to concern themselves with the implementation details of the class behind the interface. The provider of an interface can change the underlying implementations, without having to modify the programs that the interface uses. The procedural model does not have this concept of standalone interfaces.
ABAP Objects makes it easier to implement event-driven program flows. A publish-and-subscribe mechanism can loosely couple applications. The event trigger does not need to know anything about any possible handlers. This allows greater flexibility than the procedural approach, where the programs are much stronger coupled and the program flow is usually much more strictly defined.
ABAP Objects contains a small number of closely defined, mutually orthogonal, fundamental concepts, which makes it more reliable and less error-prone than classical ABAP. Classical procedural ABAP is dominated by implicit behaviors, where programs are controlled by implicit events of the runtime environment and by global data. The concepts of ABAP Objects, however, are explicitly shown in a program. ABAP Objects is easier to learn and use than classical procedural ABAP.
ABAP Objects uses cleansed syntax rules and semantics rules. Classical procedural ABAP is a language that has evolved over time, and contains several obsolete and overlapping concepts. The introduction of ABAP Objects meant that classes and methods provided a field for cleansed syntax and semantics rules, which was completely unaffected by downward compatibility requirements. This meant that most obsolete and error-prone language constructs were syntactically forbidden in ABAP Objects (within classes and methods). Also, any questionable and potentially incorrect data accesses are checked more closely and can also be forbidden. The syntax cleansing enforces the use of the ABAP language in classes, which can only be requested using the Modern ABAP guideline, outside of classes.
ABAP Objects is often the only way of dealing with new ABAP technologies. For example, GUI controls, Web Dynpro ABAP, runtime type services (RTTS), orInternet Connection Framework (ICF) only provide class-based interfaces. If programs that use these services were still implemented on a purely procedural basis, this would result in an unnecessary mix of programming models and increased complexity.
Therefore the urgent recommendation to use ABAP Objects has both formal and content-related issues:
- As described in points 1 through 5, the object-oriented programming model is better suited to keeping the complexity of software manageable through principles, such as encapsulation and inheritance. Admittedly, a good object-oriented design is not an easy task, and there are developers with only limited experience in this area even today. Given these facts, anyone who is still considering approaching a new development in the classical procedural way, must bear in mind that the procedural event-driven ABAP programming model with its system events is also not easy to understand.
- Points 6 through 8 describe more formal aspects. These points suggest that procedures should be created only as methods, even in the absence of a real object-oriented design. Function modules and subroutines should be created only in exceptional cases, where ABAP Objects does not currently provide any alternatives.
The section Object-Oriented Programming provides notes and recommendations on the optimal use of ABAP Objects.
Exception
The following properties are still missing in ABAP Objects. They are needed to replace classical processing blocks with methods:
- Remote Method Invocation (RMI) as a replacement for Remote Function Call (RFC)
- A replacement for the call of update function modules (
CALL FUNCTION IN UPDATE TASK
)
- A replacement for the call of subroutines during
COMMIT WORK
andROLLBACK WORK
(PERFORM ON COMMIT/ROLLBACK
)
- Object-oriented handling of classical dynpros, including selection screens as a replacement for dialog transactions,
CALL SCREEN
andCALL SELECTION-SCREEN
- Dynamic generation of classes as a replacement for the classical dynamic program generation (
GENERATE SUBROUTINE POOL
)
- Direct support of background processing as a replacement for the call of
- executable programs (
SUBMIT VIA JOB
)
In these cases, the following classical processing blocks can still be created in new programs:
- Function modules are still required for RFC and the update and are recommended for the call of classical dynpros and selection screens.
- Subroutines are still required for
PERFORM ON COMMIT/ROLLBACK
and in dynamically generated subroutine pools (GENERATE SUBROUTINE POOL
).
- Dialog modules and event blocks for selection screen events are still required in function groups that wrap the classical dynpros and selection screens.
- The
START-OF-SELECTION
event block is still required in executable programs that are intended for background processing.
Within this type of processing block, however, the execution should be delegated immediately to a suitable method This does not have to be a method of a global class, but it can be located in the associated main program within the scope of a local class. To ensure that the system implements the same stricter check in these processing blocks as in the methods, the obsolete statements check (OO context) can be activated in the extended program check.
Bad example
The following source code contains a rudimentary implementation for handling different types of bank
accounts in a function group and their use in a program. Only the “withdrawal of an amount”
function is shown. The function modules of the function group work on external data that is loaded into
a global internal table in the LOAD-OF-PROGRAM
event. An input parameter
checks whether money is being withdrawn from a checking account or a savings account. Next, the handling
is delegated to various subroutines using a CASE
-WHEN
control structure. No reuse takes place. The subroutines access the global internal table. The function
module for withdrawing money is called for different accounts in an application program. Classic exception
handling is performed using further CASE
-WHEN
control structures for querying sy-subrc
.
FUNCTION-POOL account.
DATA account_tab TYPE SORTED TABLE OF accounts
WITH UNIQUE KEY id.
"fetch amount for all accounts into account_tab
...
...
FUNCTION withdraw.
*"-----------------------------------------------------
*" IMPORTING
*" REFERENCE(id) TYPE accounts-id
*" REFERENCE(kind) TYPE c DEFAULT 'C'
*" REFERENCE(amount) TYPE accounts-amount
*" EXCEPTIONS
*" negative_amount
*" unknown_account_type
*"------------------------------------------------------
CASE kind.
WHEN 'C'.
PERFORM withdraw_from_checking_account
USING id amount.
WHEN 'S'.
PERFORM withdraw_from_savings_account
USING id amount.
WHEN OTHERS.
RAISE unknown_account_type.
ENDCASE.
ENDFUNCTION.
USING l_id TYPE accounts-id
l_amount TYPE accounts-amount.
FIELD-SYMBOLS <account> TYPE accounts.
ASSIGN account_tab[ KEY primary_key id = l_id ] TO <account>.
<account> = <account> - l_amount.
IF <account> < 0.
"Handle debit balance
...
ENDIF.
ENDFORM.
USING l_id TYPE accounts-id
l_amount TYPE accounts-amount.
FIELD-SYMBOLS <account> TYPE accounts.
ASSIGN account_tab[ KEY primary_key id = l_id ] TO <account>.
IF <account>-amount > l_amount.
<account>-amount = <account>-amount - l_amount.
ELSE.
RAISE negative_amount.
ENDIF.
ENDFORM.
*********************************************************
PROGRAM bank_application.
...
EXPORTING
id = ...
kind = 'C'
amount = ...
EXCEPTIONS
unknown_account_type = 2
negative_amount = 4.
CASE sy-subrc.
WHEN 2.
...
WHEN 4.
...
ENDCASE.
...
CALL FUNCTION 'WITHDRAW'
EXPORTING
id = ...
kind = 'S'
amount = ...
EXCEPTIONS
unknown_account_type = 2
negative_amount = 4.
CASE sy-subrc.
WHEN 2.
...
WHEN 4.
...
ENDCASE.
Good example
The following source code contains a rudimentary implementation for handling different types of bank accounts in classes and their use in a class. Only the “withdrawal of an amount” function is shown.
The different types of accounts are implemented in subclasses of an abstract class for accounts. Each
instance of an account is provided with the required data in its constructor. If required, the application
class generates instances of accounts of the required type and uses their methods polymorphically by
means of a superclass reference variable. Exception handling is carried out using class-based exceptions. CASE
-WHEN
control structures are not required. As already explained in
separation of concerns, no overhead code is generated here when using classes, compared to procedural programming.
INHERITING FROM cx_static_check.
ENDCLASS.
PUBLIC SECTION.
METHODS: constructor IMPORTING id TYPE string,
withdraw IMPORTING amount TYPE i
RAISING cx_negative_amount.
PROTECTED SECTION.
DATA amount TYPE accounts-amount.
ENDCLASS.
METHOD constructor.
"fetch amount for one account into attribute amount
...
ENDMETHOD.
METHOD withdraw.
me->amount = me->amount - amount.
ENDMETHOD.
ENDCLASS.
INHERITING FROM cl_account.
PUBLIC SECTION.
METHODS withdraw REDEFINITION.
ENDCLASS.
METHOD withdraw.
super->withdraw( amount ).
IF me->amount < 0.
"Handle debit balance
...
ENDIF.
ENDMETHOD.
ENDCLASS.
INHERITING FROM cl_account.
PUBLIC SECTION.
METHODS withdraw REDEFINITION.
ENDCLASS.
METHOD withdraw.
IF me->amount > amount.
super->withdraw( amount ).
ELSE.
RAISE EXCEPTION TYPE cx_negative_amount.
ENDIF.
ENDMETHOD.
ENDCLASS.
********************************************************
CLASS bank_application DEFINITION PUBLIC.
PUBLIC SECTION.
CLASS-METHODS main.
ENDCLASS.
METHOD main.
DATA: account1 TYPE REF TO cl_account,
account2 TYPE REF TO cl_account.
...
CREATE OBJECT account1 TYPE cl_checking_account
EXPORTING
id = ...
EXPORTING
id = ...
...
account1->withdraw( ... ).
account2->withdraw( ... ).
CATCH cx_negative_amount.
...
ENDTRY.
ENDMETHOD.
ENDCLASS.