| Local classes |
|
| Global classes |
|
| Addition | Notes |
| `PUBLIC` | Creates a global class |
| `FINAL` | The class does not allow inheritance. |
| `CREATE PUBLIC` | The class is instantiable anywhere. Note that not specifying a `CREATE ...` addition means the class specifies `CREATE PUBLIC` by default. |
| `CREATE PROTECTED` | The class can only be instantiated in methods of its [subclasses](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abensubclass_glosry.htm "Glossary Entry"), of the class itself, and of its [friends](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenfriend_glosry.htm "Glossary Entry"). |
| `CREATE PRIVATE` | The class can only be instantiated in methods of the class itself or of its friends. Hence, it cannot be instantiated as an inherited component of subclasses. |
| `INHERITING FROM superclass` | As the name implies, it is used to inherit from a visible [superclass](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abensuperclass_glosry.htm). If the addition is not specified, the created class implicitly inherits from the predefined empty, abstract class `object` (the root object). |
| `ABSTRACT` | To define [abstract](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenabstract_glosry.htm) classes. These classes cannot be instantiated. These classes can contain both abstract methods and non-abstract methods. Abstract methods can only be implemented in [subclasses](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abensubclass_glosry.htm) by redefinition. See a simple implementation example [here](#excursion-example-interface). |
| `[GLOBAL|LOCAL] FRIENDS class` | - Used to define [friendships](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenfriend_glosry.htm) (also possible for interfaces). Friends of a class have unrestricted access to all components of that class. - `GLOBAL FRIENDS`: Used in global classes (together with the `PUBLIC` addition) to grant friendship to other global classes and interfaces - `FRIENDS`: For local classes, e.g. local classes granting friendship to other local classes or the global class of the class pool - `LOCAL FRIENDS`: Used for global classes to grant friendship to local classes and interfaces in its own class pool. However, it is a dedicated statement, as shown in the [Friendship](#friendship) section. |
| `FOR TESTING` | For [ABAP Unit](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenabap_unit_glosry.htm) tests. Find more information in the [ABAP Unit Tests](14_ABAP_Unit_Tests.md) cheat sheet. |
| `FOR BEHAVIOR OF` | To define [ABAP behavior pools](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenbehavior_pool_glosry.htm). Find more information in the [ABAP for RAP: Entity Manipulation Language (ABAP EML)](08_EML_ABAP_for_RAP.md) cheat sheet. |
| `DEFINITION DEFERRED` | Makes a local class known in a program before the actual class definition. It is typically used in test classes of ABAP Unit. Find more information [here](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abapclass_deferred.htm). |
PUBLIC SECTION. |
Components declared in this section can be accessed from within the class and from all users of the class. |
PROTECTED SECTION. |
Components declared in this section can be accessed from within the class and subclasses as well as friends. |
PRIVATE SECTION. |
Components declared in this section can only be accessed from within the class in which they are declared and its friends. |
oref->some_static_method( ).).
- When methods are called, the (non-optional) parameters must be specified within parentheses.
- You might also stumble on method calls with the older [`CALL METHOD`](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abapcall_method_static.htm)
statements. It is recommended to use the new syntax in new developments. Note that `CALL METHOD` statements are still required in the context of [dynamic programming](06_Dynamic_Programming.md). Therefore, `CALL METHOD` statements should be reserved for dynamic method calls.
- Find an example class demonstrating various method calls in section [Excursion: Example Class](#excursion-example-class).
Examples for instance method calls and static method calls:
``` abap
"Calling instance methods via reference variable;
"within the parentheses, the parameters must be specified and assigned - if required
ref->inst_meth( ... ).
"Calling static methods via/without the class name
class_name=>stat_meth( ... ).
"Only within the program in which it is declared.
stat_meth( ... ).
"Calling (static) method having no parameter
class_name=>stat_meth( ).
"Calling (static) methods having a single importing parameter:
"Note that in the method call, the caller exports values to the
"method having importing parameters defined; hence, the addition
"EXPORTING is relevant for the caller. The following three method calls are the same
"Explicit use of EXPORTING.
class_name=>meth( EXPORTING a = b ).
"Only importing parameters in the method signature: explicit EXPORTING not needed
class_name=>meth( a = b ).
"If only a single value must be passed:
"the formal parameter name (a) and EXPORTING not needed
stat_meth( b ).
"Calling (static) methods having importing/exporting parameters
"Parameters must be specified if they are not marked as optional
class_name=>meth( EXPORTING a = b c = d "a/c: importing parameters in the method signature
IMPORTING e = f ). "e: exporting parameter in the method signature
"To store the value of the parameter, you may also declare it inline.
class_name=>meth( EXPORTING a = b c = d
IMPORTING e = DATA(z) ).
"Calling (static) methods having a changing parameter;
"should be reserved for changing an existing local variable and value
DATA h TYPE i VALUE 123.
class_name=>meth( CHANGING g = h ).
"Calling (static) methods having a returning parameter.
"Basically, they do the same as methods with exporting parameters
"but they are way more versatile, and you can save lines of code.
"They do not need temporary variables.
"In the example, the return value is stored in a variable declared inline.
"i and k are importing parameters
DATA(result) = class_name=>meth( i = j k = l ).
"They can be used with other statements, e. g. logical expressions.
"In the example below, the assumption is that the returning parameter is of type i.
IF class_name=>meth( i = j k = l ) > 100.
...
ENDIF.
"They enable method chaining.
"The example shows a method to create random integer values.
"The methods have a returning parameter.
DATA(random_no) = cl_abap_random_int=>create( )->get_next( ).
"RECEIVING parameter: Available in methods defined with a returning parameter;
"used in standalone method calls only.
"In the snippet, m is the returning parameter; n stores the result.
class_name=>meth( EXPORTING i = j k = l RECEIVING m = DATA(n) ).
```
#### Excursion: Inline Declarations, Returning Parameters
| Aspect | Notes/Code examples |
| Superclasses and subclasses |
- Inheritance means deriving any number of new classes ([subclasses](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abensubclass_glosry.htm)) from an existing class ([superclass](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abensuperclass_glosry.htm)).
- This derivation establishes a hierarchical relationship between superclasses and subclasses, forming an inheritance tree. A class can have multiple subclasses but only one direct superclass.
- A subclass can also be a superclass to multiple direct subclasses but still has only one direct superclass.
🟢 Click to expand for example codeThe inheritance tree of the example classes is as follows: `LCL1` is a superclass with direct subclasses `LCL2` and `LCL3`. `LCL3` is also a superclass from which more subclasses are derived. Similarly, `LCL5` is a superclass with `LCL6` as a direct subclass. ``` LCL1 | |--LCL2 | |--LCL3 | | | |--LCL4 | | | |--LCL5 | | | | | |--LCL6 ``` The classes are without any component specifications for demonstration purposes. ``` abap CLASS lcl1 DEFINITION CREATE PUBLIC. PUBLIC SECTION. PROTECTED SECTION. PRIVATE SECTION. ENDCLASS. CLASS lcl1 IMPLEMENTATION. ENDCLASS. CLASS lcl2 DEFINITION INHERITING FROM lcl1. PUBLIC SECTION. PROTECTED SECTION. PRIVATE SECTION. ENDCLASS. CLASS lcl2 IMPLEMENTATION. ENDCLASS. CLASS lcl3 DEFINITION INHERITING FROM lcl1. PUBLIC SECTION. PROTECTED SECTION. PRIVATE SECTION. ENDCLASS. CLASS lcl3 IMPLEMENTATION. ENDCLASS. CLASS lcl4 DEFINITION INHERITING FROM lcl3. PUBLIC SECTION. PROTECTED SECTION. PRIVATE SECTION. ENDCLASS. CLASS lcl4 IMPLEMENTATION. ENDCLASS. CLASS lcl5 DEFINITION INHERITING FROM lcl3. PUBLIC SECTION. PROTECTED SECTION. PRIVATE SECTION. ENDCLASS. CLASS lcl5 IMPLEMENTATION. ENDCLASS. CLASS lcl6 DEFINITION INHERITING FROM lcl5. PUBLIC SECTION. PROTECTED SECTION. PRIVATE SECTION. ENDCLASS. CLASS lcl6 IMPLEMENTATION. ENDCLASS. ``` |
| Components specified in superclasses |
- Subclasses inherit and therefore adopt all components, such as attributes or methods, from superclasses.
- Subclasses can use these components and add new ones.
- Subclasses know about superclass components, but superclasses do not know about subclass components, unless a friendship relationgship is defined (see further down). Generally, superclasses are unaware of their subclasses.
- By adding new components - and redefining methods, as covered below - subclasses become more specific, while superclasses remain more generic. This distinction is important for polymorphism and casting as outlined below.
- If a subclass has no additional components, it contains only the components of the superclass, except for those in the private visibility section (unless friendship is granted).
- Changes or additions to attributes in subclasses are not visible to superclasses, making these changes relevant only to the subclass and its subclasses.
🟢 Click to expand for example codeThe inheritance tree of the following example classes is as follows: ``` LCL1 | |--LCL2 | | | |--LCL3 ``` The code snippet includes various data object declarations and value assignments by exploring: - Subclasses adopt all components from the public and protected sections. The example does not cover redefining instance methods. - Adding new components. - Superclasses are unaware of their subclasses and their components. - Instance attributes are not accessible in static methods. ``` abap CLASS lcl1 DEFINITION CREATE PUBLIC. PUBLIC SECTION. DATA pub_inst_str_lcl1 TYPE string. CLASS-DATA pub_stat_str_lcl1 TYPE string. METHODS inst_meth_lcl1. CLASS-METHODS stat_meth_lcl1. PROTECTED SECTION. DATA prot_inst_str_lcl1 TYPE string. CLASS-DATA prot_stat_str_lcl1 TYPE string. PRIVATE SECTION. DATA priv_inst_str_lcl1 TYPE string. CLASS-DATA priv_stat_str_lcl1 TYPE string. ENDCLASS. CLASS lcl1 IMPLEMENTATION. METHOD inst_meth_lcl1. "Accessing attributes of the class itself pub_inst_str_lcl1 = `a`. pub_stat_str_lcl1 = `b`. prot_inst_str_lcl1 = `c`. prot_stat_str_lcl1 = `d`. priv_inst_str_lcl1 = `e`. priv_stat_str_lcl1 = `f`. "Superclasses do not know of the components of their subclasses. "Visible static, public components can be accessed using the class name "followed by => and the component name. In case of this particular "local class example, the definition part of lcl2 must be specified before "the implementation part of lcl1 for the lcl2=>pub_stat_str_lcl2 ... "statement to work. "pub_inst_str_lcl2 = `g`. "pub_stat_str_lcl2 = `h`. "prot_inst_str_lcl2 = `i`. "prot_stat_str_lcl2 = `j`. "priv_inst_str_lcl2 = `k`. "priv_stat_str_lcl2 = `l`. "lcl2=>pub_stat_str_lcl2 = `m`. ENDMETHOD. METHOD stat_meth_lcl1. "Instance attributes are not accessible in static methods. "pub_inst_str_lcl1 = `g`. pub_stat_str_lcl1 = `h`. "prot_inst_str_lcl1 = `i`. prot_stat_str_lcl1 = `j`. "priv_inst_str_lcl1 = `k`. priv_stat_str_lcl1 = `l`. ENDMETHOD. ENDCLASS. CLASS lcl2 DEFINITION INHERITING FROM lcl1. PUBLIC SECTION. DATA pub_inst_str_lcl2 TYPE string. CLASS-DATA pub_stat_str_lcl2 TYPE string. DATA added_pub_inst_str_lcl2 TYPE string. CLASS-DATA added_pub_stat_str_lcl2 TYPE string. METHODS inst_meth_lcl2. CLASS-METHODS stat_meth_lcl2. PROTECTED SECTION. DATA prot_inst_str_lcl2 TYPE string. CLASS-DATA prot_stat_str_lcl2 TYPE string. DATA added_prot_inst_str_lcl2 TYPE string. CLASS-DATA added_prot_stat_str_lcl2 TYPE string. PRIVATE SECTION. DATA priv_inst_str_lcl2 TYPE string. CLASS-DATA priv_stat_str_lcl2 TYPE string. DATA added_priv_inst_str_lcl2 TYPE string. CLASS-DATA added_priv_stat_str_lcl2 TYPE string. ENDCLASS. CLASS lcl2 IMPLEMENTATION. METHOD inst_meth_lcl2. "Accessing attributes of the class itself pub_inst_str_lcl2 = `a`. pub_stat_str_lcl2 = `b`. added_pub_inst_str_lcl2 = `c`. added_pub_stat_str_lcl2 = `d`. prot_inst_str_lcl2 = `e`. prot_stat_str_lcl2 = `f`. added_prot_inst_str_lcl2 = `g`. added_prot_stat_str_lcl2 = `h`. priv_inst_str_lcl2 = `i`. priv_stat_str_lcl2 = `j`. added_priv_inst_str_lcl2 = `k`. added_priv_stat_str_lcl2 = `l`. "Accessing attributes of the superclass pub_inst_str_lcl1 = `m`. pub_stat_str_lcl1 = `n`. prot_inst_str_lcl1 = `o`. prot_stat_str_lcl1 = `p`. "Private components of the superclass cannot be accessed "priv_inst_str_lcl1 = `q`. "priv_stat_str_lcl1 = `r`. "The following statement shows a syntax warning as an identically named "attribute as in the superclass is created. "DATA pub_inst_str_lcl1 TYPE string. "However, the following declaration using an identical name as one of the "superclass attributes is possible because the private component of the "superclass cannot be accessed. DATA priv_inst_str_lcl1 TYPE string. ENDMETHOD. METHOD stat_meth_lcl2. "Instance attributes are not accessible in static methods. "Accessing attributes of the class itself "pub_inst_str_lcl2 = `a`. pub_stat_str_lcl2 = `b`. "added_pub_inst_str_lcl2 = `c`. added_pub_stat_str_lcl2 = `d`. "prot_inst_str_lcl2 = `e`. prot_stat_str_lcl2 = `f`. "added_prot_inst_str_lcl2 = `g`. added_prot_stat_str_lcl2 = `h`. "priv_inst_str_lcl2 = `i`. priv_stat_str_lcl2 = `j`. "added_priv_inst_str_lcl2 = `k`. added_priv_stat_str_lcl2 = `l`. "Accessing attributes of the superclass "pub_inst_str_lcl1 = `m`. pub_stat_str_lcl1 = `n`. "prot_inst_str_lcl1 = `o`. prot_stat_str_lcl1 = `p`. "Private components of the superclass cannot be accessed "priv_inst_str_lcl1 = `q`. "priv_stat_str_lcl1 = `r`. ENDMETHOD. ENDCLASS. CLASS lcl3 DEFINITION INHERITING FROM lcl2. PUBLIC SECTION. DATA pub_inst_str_lcl3 TYPE string. CLASS-DATA pub_stat_str_lcl3 TYPE string. METHODS inst_meth_lcl3. CLASS-METHODS stat_meth_lcl3. PROTECTED SECTION. DATA prot_inst_str_lcl3 TYPE string. CLASS-DATA prot_stat_str_lcl3 TYPE string. PRIVATE SECTION. DATA priv_inst_str_lcl3 TYPE string. CLASS-DATA priv_stat_str_lcl3 TYPE string. ENDCLASS. CLASS lcl3 IMPLEMENTATION. METHOD inst_meth_lcl3. "Accessing attributes of the class itself pub_inst_str_lcl3 = `a`. pub_stat_str_lcl3 = `b`. prot_inst_str_lcl3 = `c`. prot_stat_str_lcl3 = `d`. priv_inst_str_lcl3 = `e`. priv_stat_str_lcl3 = `f`. "Accessing attributes of the superclasses pub_inst_str_lcl1 = `g`. pub_stat_str_lcl1 = `h`. prot_inst_str_lcl1 = `i`. prot_stat_str_lcl1 = `j`. pub_inst_str_lcl2 = `k`. pub_stat_str_lcl2 = `l`. added_pub_inst_str_lcl2 = `m`. added_pub_stat_str_lcl2 = `n`. prot_inst_str_lcl2 = `o`. prot_stat_str_lcl2 = `p`. added_prot_inst_str_lcl2 = `q`. added_prot_stat_str_lcl2 = `r`. "Private components of the superclasses cannot be accessed "priv_inst_str_lcl1 = `s`. "priv_stat_str_lcl1 = `t`. "priv_inst_str_lcl2 = `u`. "priv_stat_str_lcl2 = `v`. "added_priv_inst_str_lcl2 = `w`. "added_priv_stat_str_lcl2 = `x`. ENDMETHOD. METHOD stat_meth_lcl3. "Instance attributes are not accessible in static methods. "Accessing attributes of the class itself "pub_inst_str_lcl3 = `a`. pub_stat_str_lcl3 = `b`. "prot_inst_str_lcl3 = `c`. prot_stat_str_lcl3 = `d`. "priv_inst_str_lcl3 = `e`. priv_stat_str_lcl3 = `f`. "Accessing attributes of the superclasses "pub_inst_str_lcl1 = `g`. pub_stat_str_lcl1 = `h`. "prot_inst_str_lcl1 = `i`. prot_stat_str_lcl1 = `j`. "pub_inst_str_lcl2 = `k`. pub_stat_str_lcl2 = `l`. "added_pub_inst_str_lcl2 = `m`. added_pub_stat_str_lcl2 = `n`. "prot_inst_str_lcl2 = `o`. prot_stat_str_lcl2 = `p`. "added_prot_inst_str_lcl2 = `q`. added_prot_stat_str_lcl2 = `r`. "Private components of the superclasses cannot be accessed "priv_inst_str_lcl1 = `s`. "priv_stat_str_lcl1 = `t`. "priv_inst_str_lcl2 = `u`. "priv_stat_str_lcl2 = `v`. "added_priv_inst_str_lcl2 = `w`. "added_priv_stat_str_lcl2 = `x`. ENDMETHOD. ENDCLASS. ``` |
| Redefinition of superclass methods |
- You can (but need not) reimplement public and protected instance methods of all preceding superclasses in subclasses through redefinition (`REDEFINITION` addition), making subclasses more specific.
- Reimplementing methods allows you to reuse the parameter interface without changes.
- You can use the pseudo-reference `super->...` to call direct superclass methods while implementing redefined instance methods, which is useful for taking over, overriding, or extending implementations.
- Static methods can be accessed but not redefined.
- Changes or additions of methods in subclasses are not visible to superclasses, affecting only the class itself and its subclasses.
🟢 Click to expand for example codeThe inheritance tree of the following example classes looks as follows: ``` LCL1 | |--LCL2 | | | |--LCL3 ``` The example explores the redefinition of methods. Global class to run the example and visualize the implementations of the local classes in the CCIMP include. The output should be as follows: ``` A A1 B A12 B3 C ``` ``` abap CLASS zcl_demo_abap DEFINITION PUBLIC FINAL CREATE PUBLIC . PUBLIC SECTION. INTERFACES if_oo_adt_classrun. PROTECTED SECTION. PRIVATE SECTION. ENDCLASS. CLASS zcl_demo_abap IMPLEMENTATION. METHOD if_oo_adt_classrun~main. DATA(str1) = NEW lcl1( )->meth_lcl1( ). out->write( str1 ). DATA(str2) = NEW lcl2( )->meth_lcl1( ). out->write( str2 ). DATA(str3) = NEW lcl2( )->meth_lcl2( ). out->write( str3 ). DATA(str4) = NEW lcl3( )->meth_lcl1( ). out->write( str4 ). DATA(str5) = NEW lcl3( )->meth_lcl2( ). out->write( str5 ). DATA(str6) = NEW lcl3( )->meth_lcl3( ). out->write( str6 ). ENDMETHOD. ENDCLASS. ``` Local classes in the CCIMP include: ```abap CLASS lcl1 DEFINITION CREATE PUBLIC. PUBLIC SECTION. METHODS meth_lcl1 RETURNING VALUE(str1) TYPE string. PROTECTED SECTION. PRIVATE SECTION. ENDCLASS. CLASS lcl1 IMPLEMENTATION. METHOD meth_lcl1. str1 = `A`. ENDMETHOD. ENDCLASS. CLASS lcl2 DEFINITION INHERITING FROM lcl1. PUBLIC SECTION. METHODS meth_lcl2 RETURNING VALUE(str2) TYPE string. METHODS meth_lcl1 REDEFINITION. PROTECTED SECTION. PRIVATE SECTION. ENDCLASS. CLASS lcl2 IMPLEMENTATION. METHOD meth_lcl2. str2 = `B`. ENDMETHOD. METHOD meth_lcl1. DATA(super_str_lcl1) = super->meth_lcl1( ). str1 = super_str_lcl1 && `1`. ENDMETHOD. ENDCLASS. CLASS lcl3 DEFINITION INHERITING FROM lcl2. PUBLIC SECTION. METHODS meth_lcl3 RETURNING VALUE(str3) TYPE string. METHODS meth_lcl2 REDEFINITION. METHODS meth_lcl1 REDEFINITION. PROTECTED SECTION. PRIVATE SECTION. ENDCLASS. CLASS lcl3 IMPLEMENTATION. METHOD meth_lcl3. str3 = `C`. ENDMETHOD. METHOD meth_lcl1. DATA(super_str_lcl1) = super->meth_lcl1( ). str1 = super_str_lcl1 && `2`. ENDMETHOD. METHOD meth_lcl2. DATA(super_str_lcl2) = super->meth_lcl2( ). str2 = super_str_lcl2 && `3`. ENDMETHOD. ENDCLASS. ``` |
| Visibility of components | - Components in the public visibility section are accessible from anywhere (where visible). - Protected components are accessible by subclasses and friends. - Private components are not accessible by subclasses unless friendship is granted. - See *Components specified in superclasses* for an example. |
| Additions impacting inheritance | - You can use the `FINAL` addition to prevent classes from being inherited. - You can also apply the `FINAL` addition to methods to prevent them from being redefined in subclasses. - Refer to the next section for notes on these topics and other inheritance and instantiation features. |
| Constructors |
- Instance constructors (`constructor`):
- Subclasses cannot redefine the instance constructors of superclasses.
- These constructors are called automatically when creating an object; they cannot be called explicitly.
- In inheritance, a subclass's constructor must call all its superclasses' constructors. When you implement the instance constructor in subclasses, you must use a `super->constructor( )` call to call the direct superclass's constructor, even if the superclass does not explicitly declare it. Similarly, even if a subclass does not define and implement its constructor, the superclass's constructor will be called.
- It is required to fill any non-optional importing parameters.
- Class instantiation is controlled by specific additions (`CREATE PUBLIC/PROTECTED/PRIVATE`), affecting the ability to call constructors. The constructor's visibility cannot be more specific than the instance creator's visibility. For example, if a class is declared using `CREATE PUBLIC`, the constructor must be in the public section. If a subclass implicitly specifies `CREATE PUBLIC`, its constructor must also be public. If it specifies `CREATE PROTECTED`, the constructor can be in the public or protected section, but not private. Subclasses can specify their instantiability independently from the superclass. In classes declared using `CREATE PRIVATE`, the constructor is only visible within the class itself, unless friendship is granted. Consider making such classes final to prevent derivation.
- Static constructors (`class_constructor`):
- These constructors are implicitly available in all classes, whether declared or not.
- They are called when creating a class instance for the first time in an ABAP program or when accessing a static component, except for types and constants.
- In inheritance, static constructors in the entire inheritance tree are called first.
- A static constructor is called only once during program runtime.
- A static constructor is always public.
🟢 Example 1The inheritance tree of the following example classes is as follows: ``` LCL1 | |--LCL2 | |--LCL3 | | | |--LCL4 ``` This example explores how instance and static constructors can be specified. It shows that subclasses can determine their own instantiation independently of the superclass. The visibility of the constructor cannot be more specific than that of the `CREATE ...` specification. ``` abap CLASS lcl1 DEFINITION CREATE PUBLIC. PUBLIC SECTION. METHODS constructor. CLASS-METHODS class_constructor. PROTECTED SECTION. PRIVATE SECTION. ENDCLASS. CLASS lcl1 IMPLEMENTATION. METHOD class_constructor. ENDMETHOD. METHOD constructor. ENDMETHOD. ENDCLASS. "Implicit CREATE PUBLIC CLASS lcl2 DEFINITION INHERITING FROM lcl1. PUBLIC SECTION. METHODS constructor. CLASS-METHODS class_constructor. PROTECTED SECTION. PRIVATE SECTION. ENDCLASS. CLASS lcl2 IMPLEMENTATION. METHOD class_constructor. ENDMETHOD. METHOD constructor. super->constructor( ). ENDMETHOD. ENDCLASS. "CREATE PROTECTED CLASS lcl3 DEFINITION INHERITING FROM lcl1 CREATE PROTECTED. PUBLIC SECTION. CLASS-METHODS class_constructor. "METHODS constructor. PROTECTED SECTION. METHODS constructor. PRIVATE SECTION. ENDCLASS. CLASS lcl3 IMPLEMENTATION. METHOD class_constructor. ENDMETHOD. METHOD constructor. super->constructor( ). ENDMETHOD. ENDCLASS. "CREATE PRIVATE CLASS lcl4 DEFINITION INHERITING FROM lcl3 CREATE PRIVATE FINAL. PUBLIC SECTION. CLASS-METHODS class_constructor. METHODS constructor. PROTECTED SECTION. "METHODS constructor. PRIVATE SECTION. "METHODS constructor. ENDCLASS. CLASS lcl4 IMPLEMENTATION. METHOD class_constructor. ENDMETHOD. METHOD constructor. super->constructor( ). ENDMETHOD. ENDCLASS. "No instances of the subclass can be created. unless friendship is created *CLASS lcl5 DEFINITION INHERITING FROM lcl4. *... ``` 🟢 Example 2The inheritance tree of the following example classes is as follows: ``` LCL1 | |--LCL2 | | | |--LCL3 | | | | | |--LCL4 ``` This example explores the order of instance and static constructor calls during object creation. The constructors add strings to a string table. To visualize the output, run the global class, which includes object creations. Refer to the notes on the example output below. Global class: ```abap CLASS zcl_demo_abap DEFINITION PUBLIC FINAL CREATE PUBLIC . PUBLIC SECTION. INTERFACES if_oo_adt_classrun. PROTECTED SECTION. PRIVATE SECTION. ENDCLASS. CLASS zcl_demo_abap IMPLEMENTATION. METHOD if_oo_adt_classrun~main. DATA(oref1) = NEW lcl1( ). out->write( lcl1=>tab ). out->write( repeat( val = `_` occ = 30 ) && |\n\n| ). CLEAR lcl1=>tab. DATA(oref2) = NEW lcl2( ). out->write( lcl1=>tab ). out->write( repeat( val = `_` occ = 30 ) && |\n\n| ). CLEAR lcl1=>tab. DATA(oref3) = NEW lcl3( ). out->write( lcl1=>tab ). out->write( repeat( val = `_` occ = 30 ) && |\n\n| ). CLEAR lcl1=>tab. DATA(oref4) = NEW lcl4( ). out->write( lcl1=>tab ). ENDMETHOD. ENDCLASS. ``` Local classes in the CCIMP include: ```abap CLASS lcl1 DEFINITION CREATE PUBLIC. PUBLIC SECTION. METHODS constructor. CLASS-METHODS class_constructor. CLASS-DATA tab TYPE string_table. PROTECTED SECTION. PRIVATE SECTION. ENDCLASS. CLASS lcl1 IMPLEMENTATION. METHOD class_constructor. APPEND `lcl1 class_constructor` TO tab. ENDMETHOD. METHOD constructor. APPEND `lcl1 constructor` TO tab. ENDMETHOD. ENDCLASS. CLASS lcl2 DEFINITION INHERITING FROM lcl1. PUBLIC SECTION. METHODS constructor. CLASS-METHODS class_constructor. PROTECTED SECTION. PRIVATE SECTION. ENDCLASS. CLASS lcl2 IMPLEMENTATION. METHOD class_constructor. APPEND `lcl2 class_constructor` TO tab. ENDMETHOD. METHOD constructor. super->constructor( ). APPEND `lcl2 constructor` TO tab. ENDMETHOD. ENDCLASS. CLASS lcl3 DEFINITION INHERITING FROM lcl2. PUBLIC SECTION. METHODS constructor. CLASS-METHODS class_constructor. PROTECTED SECTION. PRIVATE SECTION. ENDCLASS. CLASS lcl3 IMPLEMENTATION. METHOD class_constructor. APPEND `lcl3 class_constructor` TO tab. ENDMETHOD. METHOD constructor. super->constructor( ). APPEND `lcl3 constructor` TO tab. ENDMETHOD. ENDCLASS. CLASS lcl4 DEFINITION INHERITING FROM lcl3. PUBLIC SECTION. METHODS constructor. CLASS-METHODS class_constructor. PROTECTED SECTION. PRIVATE SECTION. ENDCLASS. CLASS lcl4 IMPLEMENTATION. METHOD class_constructor. APPEND `lcl4 class_constructor` TO tab. ENDMETHOD. METHOD constructor. super->constructor( ). APPEND `lcl4 constructor` TO tab. ENDMETHOD. ENDCLASS. ``` Notes on the output: - When an object is created, static constructors are called first, following the inheritance tree top down. Then, instance constructors are called, also top down. - Note that when the class runs, the example is executed in a single internal session. The static constructor of a class is called only once. Therefore, you will not see `lcl1 class_constructor` in the output when creating an object of `lcl2`, and so on. ``` lcl1 class_constructor lcl1 constructor ______________________________ lcl2 class_constructor lcl1 constructor lcl2 constructor ... ``` If you comment out `DATA(oref1) = NEW lcl1( ).` and `out->write( lcl1=>tab ).`, which are the statements accessing `lcl1` for the first time, and then run the class, you will see in the output (or while debugging) that the static constructor is indeed called. The same applies to the static constructor of `lcl2`, which is not called when creating an object for `lcl3`, and so on. ``` lcl1 class_constructor lcl2 class_constructor lcl1 constructor lcl2 constructor ______________________________ ... ``` |
| `object` as root node of inheritance trees | - In inheritance trees, the root node is the predefined `object` class, representing an empty, abstract class. - If a class does not use the `INHERITING FROM` addition, it is implicitly a subclass of `object`. - The following statement uses a released ABAP class and RTTI (see the [Dynamic Programming]() cheat sheet) to determine that the root class of a class that does not explicitly inherit from another class is `object`. ``` abap DATA(superclass) = cast cl_abap_classdescr( cl_abap_typedescr=>describe_by_name( 'CL_SYSTEM_UUID' ) )->get_super_class_type( )->get_relative_name( ). ASSERT superclass = `OBJECT`. ``` |
| Syntax Example | Details |
| ``` abap CLASS zcl_demo DEFINITION PUBLIC FINAL CREATE PUBLIC . ``` |
- `... PUBLIC ...`: Specifies that the class is a global class, available globally within the class library. Most of the subsequent snippets use the `PUBLIC` addition as the focus is on global classes. - `... FINAL ...`: Specifies that the class cannot have any subclasses, effectively prohibiting inheritance. This addition seals off a branch of the inheritance tree. In final classes, all methods are automatically final. - `... CREATE PUBLIC ...`: Specifies that the class can be instantiated wherever it is visible. Not specifying the addition `CREATE ...` means `CREATE PUBLIC` by default. The following code example demonstrates local classes (no `... PUBLIC ...` addition is used): ```abap CLASS lcl1 DEFINITION FINAL CREATE PUBLIC. PUBLIC SECTION. METHODS meth1. ENDCLASS. CLASS lcl1 IMPLEMENTATION. METHOD meth1. "Creating an instance of lcl1 within the class itself. DATA(oref1) = NEW lcl1( ). ENDMETHOD. ENDCLASS. CLASS lcl2 DEFINITION FINAL CREATE PUBLIC. PUBLIC SECTION. CLASS-METHODS meth2. ENDCLASS. CLASS lcl2 IMPLEMENTATION. METHOD meth2. "Creating an instance of lcl1 wherever visible. DATA(oref2) = NEW lcl1( ). ENDMETHOD. ENDCLASS. "Inheriting from the class is not possible *CLASS lcl3 DEFINITION INHERITING FROM lcl1. * PUBLIC SECTION. *ENDCLASS. * *CLASS lcl3 IMPLEMENTATION. *ENDCLASS. ``` |
| ``` abap CLASS zcl_demo DEFINITION PUBLIC CREATE PUBLIC . ``` |
This class permits inheritance because it does not include the `FINAL` addition. Subclasses can be derived from this superclass. The following code example demonstrates local classes: ```abap CLASS lcl1 DEFINITION CREATE PUBLIC. PUBLIC SECTION. METHODS meth1. ENDCLASS. CLASS lcl1 IMPLEMENTATION. METHOD meth1. "Creating an instance of lcl1 within the class itself. DATA(oref1) = NEW lcl1( ). ENDMETHOD. ENDCLASS. CLASS lcl2 DEFINITION FINAL CREATE PUBLIC. PUBLIC SECTION. CLASS-METHODS meth2. ENDCLASS. CLASS lcl2 IMPLEMENTATION. METHOD meth2. "Creating an instance of lcl1 wherever visible. DATA(oref2) = NEW lcl1( ). ENDMETHOD. ENDCLASS. "Inheriting from the class CLASS lcl3 DEFINITION INHERITING FROM lcl1. PUBLIC SECTION. METHODS meth1 REDEFINITION. ENDCLASS. CLASS lcl3 IMPLEMENTATION. METHOD meth1. super->meth1( ). "Example instantiations (all classes allow instantation) "Note: lcl3 does not specify CREATE PUBLIC explicitly. It is "specified implicitly. DATA(oref3) = NEW lcl1( ). DATA(oref4) = NEW lcl2( ). DATA(oref5) = NEW lcl3( ). ENDMETHOD. ENDCLASS. CLASS lcl4 DEFINITION. PUBLIC SECTION. METHODS meth3. ENDCLASS. CLASS lcl4 IMPLEMENTATION. METHOD meth3. DATA(oref6) = NEW lcl3( ). DATA(oref7) = NEW lcl1( ). ENDMETHOD. ENDCLASS. ``` |
| ``` abap CLASS zcl_demo DEFINITION PUBLIC CREATE PROTECTED . ``` |
- This class permits inheritance because it does not include the `FINAL` addition. - `... CREATE PROTECTED ...`: Specifies that the class can only be instantiated within its own methods, its subclasses' methods, or those of its friends. The following code example demonstrates local classes: ```abap CLASS lcl1 DEFINITION CREATE PROTECTED. PUBLIC SECTION. METHODS meth1. ENDCLASS. CLASS lcl1 IMPLEMENTATION. METHOD meth1. "Creating an instance of lcl1 within the class itself. DATA(oref1) = NEW lcl1( ). ENDMETHOD. ENDCLASS. CLASS lcl2 DEFINITION FINAL CREATE PUBLIC. PUBLIC SECTION. CLASS-METHODS meth2. ENDCLASS. CLASS lcl2 IMPLEMENTATION. METHOD meth2. "Creating an instance of lcl1 is not possible as this class is not "a subclass or friend "DATA(oref2) = NEW lcl1( ). ENDMETHOD. ENDCLASS. "Inheriting from the class CLASS lcl3 DEFINITION INHERITING FROM lcl1. PUBLIC SECTION. METHODS meth1 REDEFINITION. ENDCLASS. CLASS lcl3 IMPLEMENTATION. METHOD meth1. super->meth1( ). "Creating an instance is possible as lcl3 is a subclass of lcl1 DATA(oref3) = NEW lcl1( ). ENDMETHOD. ENDCLASS. ********************************************************************** "Creating instances is allowed for friends "Note the DEFINITION DEFERRED additions for lcl5. It is used to make the class known in the program "before its actual definition. Such statements are particularly necessary in local classes, and if a "reference to a local class is made before it is defined. "A method of lcl5 includes the creation of an instance of lcl4, demonstrating that friends can "indeed create the instances. You can comment out FRIENDS lcl5 in the class declaration part of "lcl4. Consequently, a syntax error is displayed in lcl5 for the instance creation. CLASS lcl5 DEFINITION DEFERRED. CLASS lcl4 DEFINITION CREATE PROTECTED FRIENDS lcl5. PUBLIC SECTION. METHODS meth3. ENDCLASS. CLASS lcl4 IMPLEMENTATION. METHOD meth3. ENDMETHOD. ENDCLASS. CLASS lcl5 DEFINITION CREATE PROTECTED. PUBLIC SECTION. METHODS meth4. ENDCLASS. CLASS lcl5 IMPLEMENTATION. METHOD meth4. DATA(oref_friend) = NEW lcl4( ). ENDMETHOD. ENDCLASS. ``` |
| ``` abap CLASS zcl_demo DEFINITION FINAL CREATE PRIVATE . ``` |
- This class does not permit inheritance because it includes the `FINAL` addition. - `... CREATE PRIVATE ...`: Specifies that the class can only be instantiated within its own methods or those of its friends. It cannot be instantiated as a component of (not befriended) subclasses. - Consider the implications of defining a superclass in this manner: - External users cannot instantiate a subclass. - If inheritance is allowed, subclasses cannot instantiate themselves though. This is because they cannot access the superclass's instance constructor, preventing the creation of subclass instances. However, this can be altered if the subclass is a friend of the superclass. - Similarly, subclass objects cannot be created within their superclass if declared using `CREATE PROTECTED` or `CREATE PRIVATE`. This is only possible if the superclasses are friends with their subclasses. - The `FINAL` addition can be beneficial with `CREATE PRIVATE` to prevent the derivation of subclasses. - Note: In each class, the `CREATE PUBLIC`, `CREATE PROTECTED`, and `CREATE PRIVATE` additions of the `CLASS` statement control who can create an instance of the class and who can call its instance constructor. The following code example demonstrates local classes: ```abap CLASS lcl1 DEFINITION CREATE PRIVATE. PUBLIC SECTION. METHODS meth1. ENDCLASS. CLASS lcl1 IMPLEMENTATION. METHOD meth1. "Creating an instance of lcl1 within the class itself. DATA(oref1) = NEW lcl1( ). ENDMETHOD. ENDCLASS. "Creating instances is not possible outside the class CLASS lcl2 DEFINITION CREATE PUBLIC. PUBLIC SECTION. METHODS meth2. ENDCLASS. CLASS lcl2 IMPLEMENTATION. METHOD meth2. "Creating an instance is not possible "DATA(oref2) = NEW lcl1( ). ENDMETHOD. ENDCLASS. "Note: lcl1 is not defined as FINAL, so derivation is not explicitly "disallowed. The following class definition shows a syntax warning as "instantiation is not allowed. *CLASS lcl3 DEFINITION INHERITING FROM lcl1. * PUBLIC SECTION. *ENDCLASS. * *CLASS lcl3 IMPLEMENTATION. *ENDCLASS. ********************************************************************** "Instantiation is only possible for befriended classes "Defining another class with CREATE PRIVATE, FINAL also specified "See the notes on DEFINITION DEFERRED above. CLASS lcl5 DEFINITION DEFERRED. CLASS lcl4 DEFINITION FINAL CREATE PRIVATE FRIENDS lcl5. PUBLIC SECTION. METHODS meth3. ENDCLASS. CLASS lcl4 IMPLEMENTATION. METHOD meth3. "Creating an instance of lcl4 in the class itself. DATA(oref3) = NEW lcl4( ). "Creating an instance of lcl1 not possible outside of the class. DATA(oref4) = NEW lcl2( ). ENDMETHOD. ENDCLASS. CLASS lcl5 DEFINITION. PUBLIC SECTION. METHODS meth4. ENDCLASS. CLASS lcl5 IMPLEMENTATION. METHOD meth4. "Creating instances of lcl4 is allowed as lcl5 is befriended. DATA(oref_friend) = NEW lcl4( ). ENDMETHOD. ENDCLASS. "Another class with CREATE PRIVATE, FINAL not specified CLASS lcl7 DEFINITION DEFERRED. CLASS lcl6 DEFINITION CREATE PRIVATE FRIENDS lcl7. PUBLIC SECTION. METHODS meth5. ENDCLASS. CLASS lcl6 IMPLEMENTATION. METHOD meth5. "Creating an instance of lcl6 in the class itself. DATA(oref5) = NEW lcl6( ). ENDMETHOD. ENDCLASS. "Creating a subclass of lcl6, which is befriended CLASS lcl7 DEFINITION INHERITING FROM lcl6. PUBLIC SECTION. METHODS meth5 REDEFINITION. ENDCLASS. CLASS lcl7 IMPLEMENTATION. METHOD meth5. "Creating instances of lcl6 is allowed as lcl7 is befriended. DATA(oref_friend) = NEW lcl6( ). ENDMETHOD. ENDCLASS. ``` |
| ``` abap CLASS zcl_demo DEFINITION PUBLIC ABSTRACT CREATE ... ``` |
- `... ABSTRACT ...`:
- Defines abstract classes
- Abstract classes cannot be instantiated.
- To use the instance components of an abstract class, you can instantiate a subclass of that class.
- Abstract classes may contain both abstract and concrete instance methods. However, abstract methods are not implemented within abstract classes.
- By adding the `FINAL` addition, abstract classes can be made final. In these cases, only static components are usable. While instance components may be declared, they are not usable.
The following code example demonstrates local classes: ```abap CLASS lcl1 DEFINITION ABSTRACT CREATE PUBLIC. PUBLIC SECTION. METHODS meth1. DATA inst_attr TYPE i. ENDCLASS. CLASS lcl1 IMPLEMENTATION. METHOD meth1. "Creating an instance of lcl1 within the class itself "is not possible. Generally, abstract classes cannot be "instantiated. "DATA(oref1) = NEW lcl1( ). ENDMETHOD. ENDCLASS. "Creating instances is not possible outside the class CLASS lcl2 DEFINITION CREATE PUBLIC. PUBLIC SECTION. METHODS meth2. ENDCLASS. CLASS lcl2 IMPLEMENTATION. METHOD meth2. "Creating an instance is not possible "DATA(oref2) = NEW lcl1( ). ENDMETHOD. ENDCLASS. "Using instance components of abstract classes only via subclasses CLASS lcl3 DEFINITION INHERITING FROM lcl1. PUBLIC SECTION. METHODS meth1 REDEFINITION. ENDCLASS. CLASS lcl3 IMPLEMENTATION. METHOD meth1. ... DATA(oref3) = NEW lcl3( ). oref3->inst_attr = 1. "Creating instances of abstract classes not possible "DATA(oref4) = NEW lcl1( ). ENDMETHOD. ENDCLASS. ``` |
| ``` abap CLASS zcl_sub DEFINITION INHERITING FROM zcl_demo ... ``` |
- `... INHERITING FROM ...`:
- Can be specified in subclasses inheriting from visible superclasses
- If not specified, the class implicitly inherits from the predefined, empty, abstract class `OBJECT` (the root object).
- A subclass inherits all components of the superclasses.
- For example, if an internal table `itab` is declared as a static component in superclass `zcl_super`, subclasses can refer to `itab` directly, not necessarily by specifying the class name as with `zcl_super=>itab` (which is also possible).
- If the superclass defines a type, subclasses cannot define a type with the same name.
- The visibility of the components remains unchanged.
- Only the public and protected components of the superclass are visible in the subclass.
- Private components of superclasses are inaccessible in subclasses.
- The properties of inherited components are immutable. However, subclasses can declare additional components (with unique names) and redefine inherited methods without altering the interface.
- Upon instantiation of a subclass, all superclasses are also instantiated, ensuring the initialization of superclass attributes through calling superclass constructors.
The following code example demonstrates local classes: ```abap CLASS lcl1 DEFINITION CREATE PUBLIC. PUBLIC SECTION. METHODS meth1. DATA num1 TYPE i. CLASS-DATA str TYPE string. PROTECTED SECTION. DATA num2 TYPE i. PRIVATE SECTION. DATA num3 TYPE i. ENDCLASS. CLASS lcl1 IMPLEMENTATION. METHOD meth1. ... ENDMETHOD. ENDCLASS. "Subclasses inheriting from lcl1 CLASS lcl2 DEFINITION INHERITING FROM lcl1. PUBLIC SECTION. METHODS meth1 REDEFINITION. "Data object with the same name as specified in the superclass "is not possible in subclasses "DATA num1 TYPE i. ENDCLASS. CLASS lcl2 IMPLEMENTATION. METHOD meth1. ... "Only public and protected components can be accessed in subclasses. DATA(oref) = NEW lcl2( ). oref->num1 = 1. oref->num2 = 2. "Private components are not accessible "oref->num3 = 3. "Static attribute accessible with the name directly without class=> (which is also possible) str = `hello`. lcl1=>str = `hi`. ENDMETHOD. ENDCLASS. CLASS lcl3 DEFINITION INHERITING FROM lcl1. PUBLIC SECTION. METHODS meth1 REDEFINITION. ENDCLASS. CLASS lcl3 IMPLEMENTATION. METHOD meth1. ... ENDMETHOD. ENDCLASS. ``` |
| Syntax Example | Details |
| ``` abap METHODS some_meth FINAL ... ``` |
- Declares final methods - These methods cannot be overridden in subclasses. - Note: In final classes, all methods are inherently final. Therefore, the `FINAL` addition cannot be specified. Instance constructors are always final, but the use of the `FINAL` addition is optional. The following code example demonstrates local classes: ```abap CLASS lcl1 DEFINITION CREATE PUBLIC. PUBLIC SECTION. METHODS meth1. METHODS meth2 FINAL. ENDCLASS. CLASS lcl1 IMPLEMENTATION. METHOD meth1. ... ENDMETHOD. METHOD meth2. ... ENDMETHOD. ENDCLASS. "Subclass inheriting from lcl1 CLASS lcl2 DEFINITION INHERITING FROM lcl1. PUBLIC SECTION. METHODS meth1 REDEFINITION. "meth2 is a final method and cannot be redefined "METHODS meth2 REDEFINITION. ENDCLASS. CLASS lcl2 IMPLEMENTATION. METHOD meth1. ... ENDMETHOD. ENDCLASS. ``` |
| ``` abap METHODS some_meth ABSTRACT ... ``` |
- Declares abstract methods - Can only be used in abstract classes - You can implement these methods in a subclass (by redefining using the `REDEFINITION`addition), not in the abstract class itself. When declared, there is no implementation part in the abstract class. - All instance methods can be declared as abstract, except for instance constructors. - Private methods cannot be redefined and can therefore not be declared as abstract. - If abstract methods are declared in classes that are both abstract and final, they cannot be implemented. Therefore, the methods are not usable. - In interfaces, methods are implicitly abstract as interfaces do not contain method implementations. The following code example demonstrates local classes: ```abap CLASS lcl1 DEFINITION ABSTRACT CREATE PUBLIC. PUBLIC SECTION. METHODS meth1. METHODS meth2 ABSTRACT. DATA num TYPE i. ENDCLASS. CLASS lcl1 IMPLEMENTATION. "meth1 is a nonabstract meth METHOD meth1. ... num = 1. ENDMETHOD. "meth2 is defined as abstract and cannot be implemented "in the abstract class * METHOD meth2. * ... * ENDMETHOD. ENDCLASS. "Subclass inheriting from lcl1 CLASS lcl2 DEFINITION INHERITING FROM lcl1. PUBLIC SECTION. METHODS meth1 REDEFINITION. "The abstract method meth2 must be implemented in subclasses. METHODS meth2 REDEFINITION. ENDCLASS. CLASS lcl2 IMPLEMENTATION. METHOD meth1. ... super->meth1( ). DATA(result) = num + 1. ENDMETHOD. METHOD meth2. ... ENDMETHOD. ENDCLASS. ``` |
| ``` abap "Instance constructor METHODS constructor. "Static constructor CLASS-METHODS class_constructor. ``` |
Find information on constructors in the previous section. The following code example demonstrates constructors. When the constructors are called, a string is added to an internal table (a static attribute). You can try out the example and explore the calling of constructors as follows: 1. Create a global class that implements the class run, and add the following codes. Local classes, implemented in the CCIMP include, are called. The example is designed to write the content of the internal table to the console. ```abap CLASS zcl_demo_abap DEFINITION PUBLIC FINAL CREATE PUBLIC . PUBLIC SECTION. INTERFACES if_oo_adt_classrun. PROTECTED SECTION. PRIVATE SECTION. ENDCLASS. CLASS zcl_demo_abap IMPLEMENTATION. METHOD if_oo_adt_classrun~main. DATA(oref1) = NEW lcl2( ). DATA(tab) = lcl1=>tab. out->write( tab ). out->write( |\n| ). DATA(oref2) = NEW lcl3( ). tab = lcl1=>tab. out->write( tab ). ENDMETHOD. ENDCLASS. ``` 2. Add the following code to the CCIMP include (*Local Types* tab in ADT). ```abap CLASS lcl1 DEFINITION CREATE PUBLIC. PUBLIC SECTION. METHODS constructor. CLASS-METHODS class_constructor. CLASS-DATA tab TYPE string_table. ENDCLASS. CLASS lcl1 IMPLEMENTATION. METHOD class_constructor. APPEND `lcl1 class_constructor` TO tab. ENDMETHOD. METHOD constructor. APPEND `lcl1 constructor` TO tab. ENDMETHOD. ENDCLASS. CLASS lcl2 DEFINITION INHERITING FROM lcl1. PUBLIC SECTION. METHODS constructor. CLASS-METHODS class_constructor. ENDCLASS. CLASS lcl2 IMPLEMENTATION. METHOD class_constructor. APPEND `lcl2 class_constructor` TO tab. ENDMETHOD. METHOD constructor. super->constructor( ). APPEND `lcl2 constructor` TO tab. ENDMETHOD. ENDCLASS. CLASS lcl3 DEFINITION INHERITING FROM lcl2. PUBLIC SECTION. METHODS constructor. CLASS-METHODS class_constructor. ENDCLASS. CLASS lcl3 IMPLEMENTATION. METHOD class_constructor. APPEND `lcl3 class_constructor` TO tab. ENDMETHOD. METHOD constructor. super->constructor( ). APPEND `lcl3 constructor` TO tab. ENDMETHOD. ENDCLASS. ``` 3. Activate and go back to the global class. Choose F9 to run the example. The internal table content that is output demonstrates the sequence of constructor calls of the simple example. |
| ``` abap METHODS some_meth REDEFINITION. METHODS another_meth FINAL REDEFINITION. ``` |
- Specified in subclasses to redefine inherited methods from superclasses. - The method's implementation is expected to reimplement the inherited method. However, the subclass's new implementation conceals the superclass's implementation. - The redefined method accesses the private components of its class, not any similarly named private components in the superclass. - The superclass's implementation can be called in the redefined method using the [pseudo reference](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenpseudo_reference_glosry.htm "Glossary Entry") `super->meth( ).`. Note that non-optional importing parameters must be filled. - The redefinition is valid for subclasses until the method is redefined again. - The `FINAL` addition can be specified, preventing further redefinition of the method in other subclasses. The following code example demonstrates local classes: ```abap CLASS lcl1 DEFINITION CREATE PUBLIC. PUBLIC SECTION. METHODS meth1. METHODS meth2. ENDCLASS. CLASS lcl1 IMPLEMENTATION. METHOD meth1. ... ENDMETHOD. METHOD meth2. ... ENDMETHOD. ENDCLASS. CLASS lcl2 DEFINITION INHERITING FROM lcl1. PUBLIC SECTION. METHODS meth1 REDEFINITION. METHODS meth2 FINAL REDEFINITION. ENDCLASS. CLASS lcl2 IMPLEMENTATION. METHOD meth1. ... ENDMETHOD. METHOD meth2. ... ENDMETHOD. ENDCLASS. CLASS lcl3 DEFINITION INHERITING FROM lcl2. PUBLIC SECTION. METHODS meth1 REDEFINITION. "meth2 cannot be further redefined as it is defined as FINAL "in the class's superclass "METHODS meth2 REDEFINITION. ENDCLASS. CLASS lcl3 IMPLEMENTATION. METHOD meth1. ... ENDMETHOD. ENDCLASS. ``` |
| Class include | Code |
| Global class | ``` abap CLASS zcl_demo_abap DEFINITION PUBLIC FINAL CREATE PUBLIC . PUBLIC SECTION. INTERFACES if_oo_adt_classrun. PROTECTED SECTION. PRIVATE SECTION. ENDCLASS. CLASS zcl_demo_abap IMPLEMENTATION. METHOD if_oo_adt_classrun~main. "Object reference variables "Create object references DATA: oref1 TYPE REF TO lcl1, oref2 TYPE REF TO lcl2, oref3 TYPE REF TO lcl3, oref4 TYPE REF TO lcl4. "Creating objects oref1 = NEW #( ). oref2 = NEW #( ). oref3 = NEW #( ). oref4 = NEW #( ). "Calling redefined methods DATA text TYPE string. "A text = oref1->meth( ). "B text = oref2->meth( ). "C text = oref3->meth( ). "D text = oref4->meth( ). "Polymorphism is demonstrated as follows: A reference variable typed with "reference to a subclass can always be assigned to reference variables typed "with reference to one of its superclasses. "The following statements show upcasts using the assignment operator =. "The upcast works because the basic rule is met that the static types of the "targets are more general or identical to the static type of the sources. "Example: "- oref1 is statically typed with the type ref to lcl1. "- oref2 is statically typed with the type ref to lcl2. "- In the assignment 'oref1 = oref2.', the rule is met as the target variable's " static type of oref1 is more general (higher up in the inheritance tree). "- For the assignment to finally work, the dynamic type (which is the actual " object the object reference points to at runtime) must be the same class or one " of its subclasses. "lcl1 is the superclass of the other local classes oref1 = oref2. "B text = oref1->meth( ). oref1 = oref3. "C text = oref1->meth( ). "lcl4 is a subclass of lcl3 (and thus also from lcl1) oref1 = oref4. "D text = oref1->meth( ). oref3 = oref4. "D text = oref3->meth( ). "Upcasts also work if the static types are identical DATA(oref1b) = NEW lcl1( ). oref1 = oref1b. text = oref1->meth( ). "Re-creating objects oref1 = NEW #( ). oref2 = NEW #( ). oref3 = NEW #( ). oref4 = NEW #( ). "The following statement (basically moving down the inheritance tree) cannot "be specified using the assignment operator as there is a type conflict. "The right-hand variable's type cannot be converted to the left-hand variable's type. "If you indeed want to cast, you must perform a downcast. "oref2 = oref1. "Downcasts "Here, the static type of the target variables are more specific than the static types "of the source variables. The downcast must be triggered explicitly, e.g. by the CAST or "the older ?= operator. "However, note that the assignability is not checked until runtime. Only the syntax error "as in the previous statement is not displayed anymore. "The following example triggers a downcast explicitly. So, the syntax error from above "is not displayed. However, that does not mean that the assignment actually works. "For the downcast to work, the dynamic type must be the same class or one of its subclasses. TRY. oref2 = CAST #( oref1 ). CATCH cx_sy_move_cast_error INTO DATA(error). text = error->get_text( ). ENDTRY. "The following example performs an upcast so that the dynamic type of oref1 refers to "one of the subclasses. However, the example downcast does not work either. lcl3 (static type "of oref3) is not a subclass of lcl2 oref2 refers to. oref1 = oref3. TRY. oref2 = CAST #( oref1 ). CATCH cx_sy_move_cast_error INTO error. text = error->get_text( ). ENDTRY. "The following downcasts work because the rule is met that the dynamic type must be the same "class or one of its subclasses. "Upcast before the downcast oref1 = oref2. "Downcast (dynamic type is the same) oref2 = CAST #( oref1 ). "B text = oref2->meth( ). "Downcast (dynamic type is one of the subclasses) "Re-creating objects oref1 = NEW #( ). oref4 = NEW #( ). "lcl4 (oref4 points to) is a subclass of lcl3 (oref3 points to), and thus of lcl1 "Upcast before the downcast oref1 = oref4. "Downcast (dynamic type is one of the subclasses) oref3 = CAST #( oref1 ). "D text = oref3->meth( ). "You can check whether downcasts are possible with IF and CASE statements "Re-creating objects oref1 = NEW #( ). oref3 = NEW #( ). oref4 = NEW #( ). IF oref1 IS INSTANCE OF lcl3. oref3 = CAST #( oref1 ). text = oref3->meth( ). ELSE. "This section is executed in the example. text = `...`. ENDIF. "Upcast oref1 = oref4. CASE TYPE OF oref1. WHEN TYPE lcl3. "This section is executed in the example. oref3 = CAST #( oref1 ). "D text = oref3->meth( ). WHEN OTHERS. ... ENDCASE. ENDMETHOD. ENDCLASS. ``` |
| CCIMP include (Local Types tab in ADT) | ``` abap CLASS lcl1 DEFINITION. PUBLIC SECTION. METHODS meth RETURNING VALUE(text) TYPE string. ENDCLASS. CLASS lcl1 IMPLEMENTATION. METHOD meth. text = `A`. ENDMETHOD. ENDCLASS. CLASS lcl2 DEFINITION INHERITING FROM lcl1. PUBLIC SECTION. METHODS meth REDEFINITION. ENDCLASS. CLASS lcl2 IMPLEMENTATION. METHOD meth. text = `B`. ENDMETHOD. ENDCLASS. CLASS lcl3 DEFINITION INHERITING FROM lcl1. PUBLIC SECTION. METHODS meth REDEFINITION. ENDCLASS. CLASS lcl3 IMPLEMENTATION. METHOD meth. text = `C`. ENDMETHOD. ENDCLASS. CLASS lcl4 DEFINITION INHERITING FROM lcl3. PUBLIC SECTION. METHODS meth REDEFINITION. ENDCLASS. CLASS lcl4 IMPLEMENTATION. METHOD meth. text = `D`. ENDMETHOD. ENDCLASS. ``` |
| Class include | Code |
| Global class | ``` abap CLASS zcl_demo_abap DEFINITION PUBLIC FINAL CREATE PUBLIC . PUBLIC SECTION. INTERFACES if_oo_adt_classrun. PROTECTED SECTION. PRIVATE SECTION. ENDCLASS. CLASS zcl_demo_abap IMPLEMENTATION. METHOD if_oo_adt_classrun~main. "Object reference variables "Creating object references DATA: "lcl1 implements the interface lif "Up to oref4, the classes are in an inheritance relationship oref1 TYPE REF TO lcl1, oref2 TYPE REF TO lcl2, oref3 TYPE REF TO lcl3, oref4 TYPE REF TO lcl4, "Implements the interface lif but is not in the inheritance relationship above oref5 TYPE REF TO lcl5, "Interface reference variable iref TYPE REF TO lif. "Creating objects oref1 = NEW #( ). oref2 = NEW #( ). oref3 = NEW #( ). oref4 = NEW #( ). oref5 = NEW #( ). "Calling redefined methods DATA text TYPE string. "A text = oref1->lif~meth( ). "B text = oref2->lif~meth( ). "C text = oref3->lif~meth( ). "D text = oref4->lif~meth( ). "E text = oref5->lif~meth( ). "The static type can also refer to an interface. "Assignments "The static types of the example reference variables refer to classes "that implement the interface and are in an inheritance relationship. iref = oref1. "A text = iref->meth( ). iref = oref2. "B text = iref->meth( ). iref = oref3. "C text = iref->meth( ). iref = oref4. "D text = iref->meth( ). "Example class that implements the interface iref = oref5. "E text = iref->meth( ). "Both lcl1 (oref1) and lcl5 (oref5) implement the interface lif, "so the assignment works as the static type of the interface reference "variables is the same. DATA irefb TYPE REF TO lif. iref = oref1. irefb = oref5. iref = irefb. "Downcasts "Upcast before the downcast iref = oref4. "The following statement triggers a sytax error "oref3 = iref. oref3 = CAST #( iref ). "D text = oref3->lif~meth( ). "Downcast not possible because the dynamic type is not the same or a subclass TRY. iref = oref2. oref3 = CAST #( iref ). CATCH cx_sy_move_cast_error INTO DATA(error). text = error->get_text( ). ENDTRY. ENDMETHOD. ENDCLASS. ``` |
| CCIMP include (Local Types tab in ADT) | ``` abap INTERFACE lif. METHODS meth RETURNING VALUE(text) TYPE string. ENDINTERFACE. CLASS lcl1 DEFINITION. PUBLIC SECTION. INTERFACES lif. ENDCLASS. CLASS lcl1 IMPLEMENTATION. METHOD lif~meth. text = `A`. ENDMETHOD. ENDCLASS. CLASS lcl2 DEFINITION INHERITING FROM lcl1. PUBLIC SECTION. METHODS lif~meth REDEFINITION. ENDCLASS. CLASS lcl2 IMPLEMENTATION. METHOD lif~meth. text = `B`. ENDMETHOD. ENDCLASS. CLASS lcl3 DEFINITION INHERITING FROM lcl1. PUBLIC SECTION. METHODS lif~meth REDEFINITION. ENDCLASS. CLASS lcl3 IMPLEMENTATION. METHOD lif~meth. text = `C`. ENDMETHOD. ENDCLASS. CLASS lcl4 DEFINITION INHERITING FROM lcl3. PUBLIC SECTION. METHODS lif~meth REDEFINITION. ENDCLASS. CLASS lcl4 IMPLEMENTATION. METHOD lif~meth. text = `D`. ENDMETHOD. ENDCLASS. CLASS lcl5 DEFINITION. PUBLIC SECTION. INTERFACES lif. ENDCLASS. CLASS lcl5 IMPLEMENTATION. METHOD lif~meth. text = `E`. ENDMETHOD. ENDCLASS. ``` |
| Addition | Notes |
| [`ALIASES ... FOR ...`](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abapaliases.htm) |
Specifies alias names for the interface components. The components can then be addressed using the alias name.
```abap "Local interface in a CCIMP include INTERFACE lif. METHODS some_method. DATA some_string type string. ENDINTERFACE. "Local class in a CCIMP include implementing the interface CLASS lcl DEFINITION. PUBLIC SECTION. INTERFACES lif. ALIASES meth FOR lif~some_method. ALIASES str FOR lif~some_string. ENDCLASS. CLASS lcl IMPLEMENTATION. METHOD meth. "The following syntax is also possible: METHOD lif~some_method. ... DATA(string1) = str. "The following sytanx is also possible. However, when you have already addressed the component "with the alias as in the assignment above, the following statement shows a syntax warning. "DATA(string2) = lif~some_string. ENDMETHOD. ENDCLASS. ``` |
| [`ABSTRACT METHODS`](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abapinterfaces_class.htm) |
- Specifies instance methods as abstract.
- Multiple methods can be specified.
- The addition can only be used when the whole class is defined as abstract.
``` abap INTERFACE lif. METHODS meth1. METHODS meth2. ENDINTERFACE. "Local abstract class "meth1 is specified as abstract method, meth2 is not. "Therefore, only meth2 must be implemented. meth1 must "be implemented by the subclasses. CLASS lcl1 DEFINITION ABSTRACT. PUBLIC SECTION. INTERFACES lif ABSTRACT METHODS meth1. ENDCLASS. CLASS lcl1 IMPLEMENTATION. METHOD lif~meth2. ... ENDMETHOD. ENDCLASS. CLASS lcl2 DEFINITION INHERITING FROM lcl1. PUBLIC SECTION. METHODS lif~meth1 REDEFINITION. METHODS lif~meth2 REDEFINITION. ENDCLASS. CLASS lcl2 IMPLEMENTATION. METHOD lif~meth1. ... ENDMETHOD. METHOD lif~meth2. ... ENDMETHOD. ENDCLASS. ``` |
| [`ALL METHODS ABSTRACT`](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abapinterfaces_class.htm) |
See above. With this addition, all methods are specified as abstract.
``` abap INTERFACE lif. METHODS meth1. METHODS meth2. ENDINTERFACE. "Local abstract class "All methods are specified as abstract methods. "Therefore, all methods of the interface must be implemented "by the subclasses. CLASS lcl1 DEFINITION ABSTRACT. PUBLIC SECTION. INTERFACES lif ALL METHODS ABSTRACT. ENDCLASS. CLASS lcl1 IMPLEMENTATION. ENDCLASS. CLASS lcl2 DEFINITION INHERITING FROM lcl1. PUBLIC SECTION. METHODS lif~meth1 REDEFINITION. METHODS lif~meth2 REDEFINITION. ENDCLASS. CLASS lcl2 IMPLEMENTATION. METHOD lif~meth1. ... ENDMETHOD. METHOD lif~meth2. ... ENDMETHOD. ENDCLASS. ``` |
| [`FINAL METHODS`](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abapinterfaces_class.htm) |
Specifies methods as final so they cannot be further redefined. Multiple methods can be specified.
```abap INTERFACE lif. METHODS meth1. METHODS meth2. ENDINTERFACE. "meth1 is specified as final method, meth2 is not. "Therefore, only meth2 can be further redefined in subclasses. CLASS lcl1 DEFINITION. PUBLIC SECTION. INTERFACES lif FINAL METHODS meth1. ENDCLASS. CLASS lcl1 IMPLEMENTATION. METHOD lif~meth1. ... ENDMETHOD. METHOD lif~meth2. ... ENDMETHOD. ENDCLASS. CLASS lcl2 DEFINITION INHERITING FROM lcl1. PUBLIC SECTION. "meth1 cannot be redefined as it is declared as final in the superclass. "METHODS lif~meth1 REDEFINITION. METHODS lif~meth2 REDEFINITION. ENDCLASS. CLASS lcl2 IMPLEMENTATION. METHOD lif~meth2. ... ENDMETHOD. ENDCLASS. ``` |
| [`ALL METHODS FINAL`](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abapinterfaces_class.htm) |
See above. With this addition, all methods are specified as final.
``` abap INTERFACE lif. METHODS meth1. METHODS meth2. ENDINTERFACE. "All methods are specified as final. Therefore, they "cannot be further redefined in subclasses. CLASS lcl1 DEFINITION. PUBLIC SECTION. INTERFACES lif ALL METHODS FINAL. METHODS meth3. ENDCLASS. CLASS lcl1 IMPLEMENTATION. METHOD lif~meth1. ... ENDMETHOD. METHOD lif~meth2. ... ENDMETHOD. METHOD meth3. ... ENDMETHOD. ENDCLASS. CLASS lcl2 DEFINITION INHERITING FROM lcl1. PUBLIC SECTION. "meth1 and meth2 cannot be redefined. "METHODS lif~meth1 REDEFINITION. "METHODS lif~meth2 REDEFINITION. METHODS meth3 REDEFINITION. ENDCLASS. CLASS lcl2 IMPLEMENTATION. METHOD meth3. ... ENDMETHOD. ENDCLASS. ``` |
| [`DATA VALUES`](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/ABAPINTERFACES_CLASS.html) |
- Used to assign start values for attributes
- Works in the style of `DATA ... VALUE ...` statements, e.g. `DATA number TYPE i VALUE 123`.
``` abap INTERFACE lif. METHODS meth1 RETURNING VALUE(result) TYPE i. DATA num1 TYPE i. DATA num2 TYPE i. CLASS-DATA num3 TYPE i. ENDINTERFACE. CLASS lcl1 DEFINITION. PUBLIC SECTION. INTERFACES lif DATA VALUES num1 = 1 num2 = 3 num3 = 6. ENDCLASS. CLASS lcl1 IMPLEMENTATION. METHOD lif~meth1. result = lif~num1 + lif~num2 + lif~num3. ENDMETHOD. ENDCLASS. CLASS lcl3 DEFINITION. PUBLIC SECTION. CLASS-METHODS meth. ENDCLASS. CLASS lcl3 IMPLEMENTATION. METHOD meth. "result: 10 DATA(result) = NEW lcl1( )->lif~meth1( ). ENDMETHOD. ENDCLASS. ``` |
| [`PARTIALLY IMPLEMENTED`](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/ABAPINTERFACES_PARTIALLY.html) |
- Relevant only for test classes.
- When you use the `PARTIALLY IMPLEMENTED` addition in test classes, you are not forced to implement all of the concrete non-optional methods.
- It is particularly useful for interfaces to implement test doubles, and not all methods are necessary.
- See the [ABAP Unit Tests](14_ABAP_Unit_Tests.md) cheat sheet.
``` abap "Test double class in a test include CLASS ltd_test_double DEFINITION FOR TESTING. PUBLIC SECTION. INTERFACES some_intf PARTIALLY IMPLEMENTED. ENDCLASS. CLASS ltd_test_double IMPLEMENTATION. METHOD some_intf~some_meth. ... ENDMETHOD. ENDCLASS. ``` |
|
[`DEFAULT IGNORE`](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abapmethods_default.htm)
(addition used in the interface definition) |
- Marks the implementation of methods as optional
- Defines a default behavior when non-implemented methods are called. When a method with such a declaration is called without an implementation, it behaves as though no implementation exists.
- Can only be used in interfaces for instance and static methods (except constructors and test methods)
``` abap INTERFACE lif. METHODS meth1 DEFAULT IGNORE. METHODS meth2. ENDINTERFACE. CLASS lcl1 DEFINITION. PUBLIC SECTION. INTERFACES lif. ENDCLASS. "The class implementation does not include the optional "implementation of lif~meth1. CLASS lcl1 IMPLEMENTATION. METHOD lif~meth2. ... ENDMETHOD. ENDCLASS. CLASS lcl2 DEFINITION. PUBLIC SECTION. INTERFACES lif. ENDCLASS. "The class implementation includes the optional "implementation of lif~meth1. CLASS lcl2 IMPLEMENTATION. METHOD lif~meth1. ... ENDMETHOD. METHOD lif~meth2. ... ENDMETHOD. ENDCLASS. CLASS lcl3 DEFINITION. PUBLIC SECTION. class-methods meth3. ENDCLASS. "The class implementation includes the optional "implementation of lif~meth1. CLASS lcl3 IMPLEMENTATION. METHOD meth3. DATA(oref1) = NEW lcl1( ). DATA(oref2) = NEW lcl2( ). "Although not implemented, meth1 can be specified to be called. "In this case, it is just like calling a method with empty implementation. oref1->lif~meth1( ). oref1->lif~meth2( ). "In this class, both methods are implemented. oref2->lif~meth1( ). oref2->lif~meth2( ). ENDMETHOD. ENDCLASS. ``` |
|
[`DEFAULT FAIL`](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abapmethods_default.htm)
(addition used in the interface definition) |
See above. The behavior with this addition is that when an unimplemented method is called, the `CX_SY_DYN_CALL_ILLEGAL_METHOD` exception is raised.
``` abap INTERFACE lif. METHODS meth1 DEFAULT FAIL. METHODS meth2. ENDINTERFACE. CLASS lcl1 DEFINITION. PUBLIC SECTION. INTERFACES lif. ENDCLASS. "The class implementation does not include the optional "implementation of lif~meth1. CLASS lcl1 IMPLEMENTATION. METHOD lif~meth2. ... ENDMETHOD. ENDCLASS. CLASS lcl2 DEFINITION. PUBLIC SECTION. INTERFACES lif. ENDCLASS. "The class implementation includes the optional "implementation of lif~meth1. CLASS lcl2 IMPLEMENTATION. METHOD lif~meth1. ... ENDMETHOD. METHOD lif~meth2. ... ENDMETHOD. ENDCLASS. CLASS lcl3 DEFINITION. PUBLIC SECTION. CLASS-METHODS meth3. ENDCLASS. CLASS lcl3 IMPLEMENTATION. METHOD meth3. DATA(oref1) = NEW lcl1( ). DATA(oref2) = NEW lcl2( ). "Although not implemented, meth1 can be specified to be called. "However, with the DEFAULT FAIL addition, an exception is "raised. TRY. oref1->lif~meth1( ). CATCH cx_sy_dyn_call_illegal_method INTO DATA(error). DATA(error_text) = error->get_text( ). ENDTRY. oref1->lif~meth2( ). "In this class, both methods are implemented. oref2->lif~meth1( ). oref2->lif~meth2( ). ENDMETHOD. ENDCLASS. ``` |
| Class include | Code |
| Global class |
- Create a new global class (the example uses the name `zcl_demo_abap`) and copy and paste the following code in the *Global Class* tab in ADT.
- The class has a type and method declaration in the private section. They are used in the local class.
- Once activated (and the code of the other includes has been inserted), you can choose *F9* in ADT to run the class.
- When running the class, a method of the local class that is declared in the private section there is called. As a result of this method call, a string is assigned to an attribute that is also declared in the private section of the local class. This attribute is accessed by the global class, and finally displayed in the ADT console.
```abap CLASS zcl_demo_abap DEFINITION PUBLIC FINAL CREATE PUBLIC . PUBLIC SECTION. INTERFACES if_oo_adt_classrun. PROTECTED SECTION. PRIVATE SECTION. TYPES str TYPE string. CLASS-METHODS get_hello RETURNING VALUE(hello) TYPE str. ENDCLASS. CLASS zcl_demo_abap IMPLEMENTATION. METHOD if_oo_adt_classrun~main. local_class=>say_hello( ). DATA(hello) = local_class=>hello. out->write( hello ). ENDMETHOD. METHOD get_hello. hello = `Hello`. ENDMETHOD. ENDCLASS. ``` |
| CCDEF include (Class-relevant Local Types tab in ADT) |
- Regarding the includes, see the information in section [Excursion: Class Pool and Include Programs](#excursion-class-pool-and-include-programs)
- The `LOCAL FRIENDS` addition makes the local class a friend of the global class. The private components of the global class can then be accessed by the local class.
```abap CLASS local_class DEFINITION DEFERRED. CLASS zcl_demo_abap DEFINITION LOCAL FRIENDS local_class. ``` |
| CCIMP include (Local Types tab in ADT) |
- The `FRIENDS` addition makes the global class a friend of the local class. The private components of the local class can then be accessed by the global class.
- A type declared in the private section of the global class is used to type an attribute.
- The method, which is also declared in the private section, includes a method call in the implementation. It is a method declared in the private section of the global class.
```abap CLASS local_class DEFINITION FRIENDS zcl_demo_abap. PUBLIC SECTION. PROTECTED SECTION. PRIVATE SECTION. CLASS-DATA hello TYPE zcl_demo_abap=>str. CLASS-METHODS say_hello. ENDCLASS. CLASS local_class IMPLEMENTATION. METHOD say_hello. hello = |{ zcl_demo_abap=>get_hello( ) } { sy-uname }.|. ENDMETHOD. ENDCLASS. ``` |
| Class include | Code |
| Global class | ``` abap CLASS zcl_demo_abap DEFINITION PUBLIC FINAL CREATE PUBLIC . PUBLIC SECTION. INTERFACES if_oo_adt_classrun. PROTECTED SECTION. PRIVATE SECTION. ENDCLASS. CLASS zcl_demo_abap IMPLEMENTATION. METHOD if_oo_adt_classrun~main. "Saying hello in English DATA(oref_en) = lcl_factory_cl=>create_hello( lif_factory=>en ). DATA(hello_en) = oref_en->say_hello( ). out->write( hello_en ). "Saying hello in French DATA(oref_fr) = lcl_factory_cl=>create_hello( lif_factory=>fr ). DATA(hello_fr) = oref_fr->say_hello( ). out->write( hello_fr ). "Saying hello in Italian DATA(oref_it) = lcl_factory_cl=>create_hello( lif_factory=>it ). DATA(hello_it) = oref_it->say_hello( ). out->write( hello_it ). "Saying hello in Spanish DATA(oref_es) = lcl_factory_cl=>create_hello( lif_factory=>es ). DATA(hello_es) = oref_es->say_hello( ). out->write( hello_es ). "Saying hello in German DATA(oref_de) = lcl_factory_cl=>create_hello( lif_factory=>de ). DATA(hello_de) = oref_de->say_hello( ). out->write( hello_de ). "Default hello DATA(oref_default) = lcl_factory_cl=>create_hello( lif_factory=>init ). DATA(hello_default) = oref_default->say_hello( ). out->write( hello_default ). ENDMETHOD. ENDCLASS. ``` |
| CCIMP include (Local Types tab in ADT) | ``` abap INTERFACE lif_factory. TYPES: basetype TYPE i, BEGIN OF ENUM enum_langu BASE TYPE basetype, init VALUE IS INITIAL, en VALUE 1, fr VALUE 2, it VALUE 3, es VALUE 4, de VALUE 5, END OF ENUM enum_langu. METHODS say_hello RETURNING VALUE(hi) TYPE string. ENDINTERFACE. CLASS lcl_en DEFINITION FINAL CREATE PUBLIC. PUBLIC SECTION. INTERFACES lif_factory. PROTECTED SECTION. PRIVATE SECTION. ENDCLASS. CLASS lcl_en IMPLEMENTATION. METHOD lif_factory~say_hello. hi = `Hi`. ENDMETHOD. ENDCLASS. CLASS lcl_fr DEFINITION FINAL CREATE PUBLIC. PUBLIC SECTION. INTERFACES lif_factory. PROTECTED SECTION. PRIVATE SECTION. ENDCLASS. CLASS lcl_fr IMPLEMENTATION. METHOD lif_factory~say_hello. hi = `Salut`. ENDMETHOD. ENDCLASS. CLASS lcl_it DEFINITION FINAL CREATE PUBLIC. PUBLIC SECTION. INTERFACES lif_factory. PROTECTED SECTION. PRIVATE SECTION. ENDCLASS. CLASS lcl_it IMPLEMENTATION. METHOD lif_factory~say_hello. hi = `Ciao`. ENDMETHOD. ENDCLASS. CLASS lcl_es DEFINITION FINAL CREATE PUBLIC. PUBLIC SECTION. INTERFACES lif_factory. PROTECTED SECTION. PRIVATE SECTION. ENDCLASS. CLASS lcl_es IMPLEMENTATION. METHOD lif_factory~say_hello. hi = `Hola`. ENDMETHOD. ENDCLASS. CLASS lcl_de DEFINITION FINAL CREATE PUBLIC. PUBLIC SECTION. INTERFACES lif_factory. PROTECTED SECTION. PRIVATE SECTION. ENDCLASS. CLASS lcl_de IMPLEMENTATION. METHOD lif_factory~say_hello. hi = `Hallo`. ENDMETHOD. ENDCLASS. ********************************************************************** CLASS lcl_factory_cl DEFINITION FINAL CREATE PRIVATE. PUBLIC SECTION. CLASS-METHODS create_hello IMPORTING language TYPE lif_factory=>enum_langu RETURNING VALUE(hello) TYPE REF TO lif_factory. PROTECTED SECTION. PRIVATE SECTION. ENDCLASS. CLASS lcl_factory_cl IMPLEMENTATION. METHOD create_hello. hello = SWITCH #( language WHEN lif_factory=>en THEN NEW lcl_en( ) WHEN lif_factory=>fr THEN NEW lcl_fr( ) WHEN lif_factory=>it THEN NEW lcl_it( ) WHEN lif_factory=>es THEN NEW lcl_es( ) WHEN lif_factory=>de THEN NEW lcl_de( ) "E.g. raising an exception or returning a default object ELSE NEW lcl_en( ) ). ENDMETHOD. ENDCLASS. ``` |
| Class include | Code |
| Global class | ``` abap CLASS zcl_demo_abap DEFINITION PUBLIC FINAL CREATE PUBLIC . PUBLIC SECTION. INTERFACES if_oo_adt_classrun. PROTECTED SECTION. PRIVATE SECTION. ENDCLASS. CLASS zcl_demo_abap IMPLEMENTATION. METHOD if_oo_adt_classrun~main. "Internal table to store and display object reference variable names and "time stamp values TYPES: BEGIN OF s_ts, name TYPE string, timestamp_static TYPE utclong, timestamp_instance TYPE utclong, END OF s_ts. DATA ts_tab TYPE TABLE OF s_ts WITH EMPTY KEY. "Object creation as follows is not possible "DATA(oref) = NEW lcl_singleton( ). "Creating object DATA(oref1) = lcl_singleton=>get_obj( ). "Retrieving time stamps, and adding the values to the internal table created above "for display purposes oref1->get_timestamps( IMPORTING ts_static = DATA(ts_static) ts_instance = DATA(ts_instance) ). APPEND VALUE #( name = `oref1` timestamp_static = ts_static timestamp_instance = ts_instance ) TO ts_tab. "Adding entries to a log table (represented by a private static attribute in the local class) oref1->add_log( |Text 1 added at { utclong_current( ) } (using oref1)| ). oref1->add_log( |Text 2 added at { utclong_current( ) } (using oref1)| ). "Creating more objects (however, the one created previously is returned) and adding entries "to the log table "Time stamp values are also added the to the internal table for display purposes DATA(oref2) = lcl_singleton=>get_obj( ). oref2->get_timestamps( IMPORTING ts_static = ts_static ts_instance = ts_instance ). APPEND VALUE #( name = `oref2` timestamp_static = ts_static timestamp_instance = ts_instance ) TO ts_tab. oref2->add_log( |Text 3 added at { utclong_current( ) } (using oref2)| ). oref2->add_log( |Text 4 added at { utclong_current( ) } (using oref2)| ). oref1->add_log( |Text 5 added at { utclong_current( ) } (using oref1)| ). DATA(oref3) = lcl_singleton=>get_obj( ). oref3->get_timestamps( IMPORTING ts_static = ts_static ts_instance = ts_instance ). APPEND VALUE #( name = `oref3` timestamp_static = ts_static timestamp_instance = ts_instance ) TO ts_tab. oref3->add_log( |Text 6 added at { utclong_current( ) } (using oref3)| ). oref3->add_log( |Text 7 added at { utclong_current( ) } (using oref3)| ). oref1->add_log( |Text 8 added at { utclong_current( ) } (using oref1)| ). oref2->add_log( |Text 9 added at { utclong_current( ) } (using oref2)| ). oref3->add_log( |Text 10 added at { utclong_current( ) } (using oref3)| ). DATA(oref4) = lcl_singleton=>get_obj( ). oref4->get_timestamps( IMPORTING ts_static = ts_static ts_instance = ts_instance ). APPEND VALUE #( name = `oref4` timestamp_static = ts_static timestamp_instance = ts_instance ) TO ts_tab. oref4->add_log( |Text 11 added at { utclong_current( ) } (using oref4)| ). oref4->add_log( |Text 12 added at { utclong_current( ) } (using oref4)| ). "Retrieving the content of the log table per object "However, as it is one and the same object that is dealt with, the content is the same. DATA(log1) = oref1->get_log( ). DATA(log2) = oref2->get_log( ). DATA(log3) = oref3->get_log( ). out->write( log1 ). out->write( |\n| ). ASSERT log1 = log2. ASSERT log1 = log3. "Displaying the time stamps visualizing the singleton pattern SORT ts_tab BY name ASCENDING. out->write( ts_tab ). ENDMETHOD. ENDCLASS. ``` |
| CCIMP include (Local Types tab in ADT) | ``` abap CLASS lcl_singleton DEFINITION CREATE PRIVATE. PUBLIC SECTION. CLASS-METHODS get_obj RETURNING VALUE(obj) TYPE REF TO lcl_singleton. METHODS add_log IMPORTING text TYPE string. METHODS get_log RETURNING VALUE(log) TYPE string_table. METHODS get_timestamps EXPORTING ts_static TYPE utclong ts_instance TYPE utclong. CLASS-METHODS class_constructor. METHODS constructor. PROTECTED SECTION. PRIVATE SECTION. CLASS-DATA oref TYPE REF TO lcl_singleton. CLASS-DATA log_table TYPE string_table. CLASS-DATA timestamp_static TYPE utclong. DATA timestamp_instance TYPE utclong. ENDCLASS. CLASS lcl_singleton IMPLEMENTATION. METHOD get_obj. IF oref IS NOT BOUND. oref = NEW lcl_singleton( ). ENDIF. obj = oref. ENDMETHOD. METHOD add_log. INSERT text INTO TABLE log_table. ENDMETHOD. METHOD get_log. log = log_table. ENDMETHOD. METHOD get_timestamps. ts_static = timestamp_static. ts_instance = timestamp_instance. ENDMETHOD. METHOD class_constructor. timestamp_static = utclong_current( ). ENDMETHOD. METHOD constructor. timestamp_instance = utclong_current( ). ENDMETHOD. ENDCLASS. ``` |
| Class include | Code |
| Global class | ``` abap CLASS zcl_demo_abap DEFINITION PUBLIC FINAL CREATE PUBLIC . PUBLIC SECTION. INTERFACES if_oo_adt_classrun. PROTECTED SECTION. PRIVATE SECTION. ENDCLASS. CLASS zcl_demo_abap IMPLEMENTATION. METHOD if_oo_adt_classrun~main. DATA(italian_menu) = NEW menu_provider( customer_order=>place_order( menu_factory=>italian ) )->create_menu( ). out->write( data = italian_menu name = `italian_menu` ). out->write( |\n| ). DATA(seafood_menu) = NEW menu_provider( customer_order=>place_order( menu_factory=>seafood ) )->create_menu( ). out->write( data = seafood_menu name = `seafood_menu` ). out->write( |\n| ). DATA(vegan_menu) = NEW menu_provider( customer_order=>place_order( menu_factory=>vegan ) )->create_menu( ). out->write( data = vegan_menu name = `vegan_menu` ). out->write( |\n| ). ENDMETHOD. ENDCLASS. ``` |
| CCIMP include (Local Types tab in ADT) | ``` abap *&---------------------------------------------------------------------* *& Abstract products *&---------------------------------------------------------------------* CLASS starters DEFINITION ABSTRACT. PUBLIC SECTION. METHODS get_starters ABSTRACT RETURNING VALUE(starters) TYPE string_table. ENDCLASS. CLASS main_dishes DEFINITION ABSTRACT. PUBLIC SECTION. METHODS get_main_dishes ABSTRACT RETURNING VALUE(main_dishes) TYPE string_table. ENDCLASS. CLASS desserts DEFINITION ABSTRACT. PUBLIC SECTION. METHODS get_desserts ABSTRACT RETURNING VALUE(desserts) TYPE string_table. ENDCLASS. *&---------------------------------------------------------------------* *& Concrete products *&---------------------------------------------------------------------* CLASS starters_italian DEFINITION INHERITING FROM starters. PUBLIC SECTION. METHODS get_starters REDEFINITION. ENDCLASS. CLASS starters_italian IMPLEMENTATION. METHOD get_starters. starters = VALUE #( ( `Bruschetta (1)` ) ( `Caprese salad (1)` ) ( `Antipasto platter (1)` ) ). ENDMETHOD. ENDCLASS. CLASS starters_vegan DEFINITION INHERITING FROM starters. PUBLIC SECTION. METHODS get_starters REDEFINITION. ENDCLASS. CLASS starters_vegan IMPLEMENTATION. METHOD get_starters. starters = VALUE #( ( `Stuffed mushrooms (1)` ) ( `Zucchini fritters (1)` ) ( `Tomato soup (1)` ) ). ENDMETHOD. ENDCLASS. CLASS starters_seafood DEFINITION INHERITING FROM starters. PUBLIC SECTION. METHODS get_starters REDEFINITION. ENDCLASS. CLASS starters_seafood IMPLEMENTATION. METHOD get_starters. starters = VALUE #( ( `Shrimp cocktail (1)` ) ( `Crab cakes (1)` ) ( `Calamari (1)` ) ). ENDMETHOD. ENDCLASS. CLASS main_dishes_italian DEFINITION INHERITING FROM main_dishes. PUBLIC SECTION. METHODS get_main_dishes REDEFINITION. ENDCLASS. CLASS main_dishes_italian IMPLEMENTATION. METHOD get_main_dishes. main_dishes = VALUE #( ( `Spaghetti Carbonara (2)` ) ( `Lasagna alla Bolognese (2)` ) ( `Saltimbocca alla Romana (2)` ) ). ENDMETHOD. ENDCLASS. CLASS main_dishes_vegan DEFINITION INHERITING FROM main_dishes. PUBLIC SECTION. METHODS get_main_dishes REDEFINITION. ENDCLASS. CLASS main_dishes_vegan IMPLEMENTATION. METHOD get_main_dishes. main_dishes = VALUE #( ( `Chickpea curry (2)` ) ( `Cauliflower steak (2)` ) ( `Vegan burger (2)` ) ). ENDMETHOD. ENDCLASS. CLASS main_dishes_seafood DEFINITION INHERITING FROM main_dishes. PUBLIC SECTION. METHODS get_main_dishes REDEFINITION. ENDCLASS. CLASS main_dishes_seafood IMPLEMENTATION. METHOD get_main_dishes. main_dishes = VALUE #( ( `Baked salmon (2)` ) ( `Grilled lobster (2)` ) ( `Fish and chips (2)` ) ). ENDMETHOD. ENDCLASS. CLASS desserts_italian DEFINITION INHERITING FROM desserts. PUBLIC SECTION. METHODS get_desserts REDEFINITION. ENDCLASS. CLASS desserts_italian IMPLEMENTATION. METHOD get_desserts. desserts = VALUE #( ( `Tiramisu (3)` ) ( `Panna cotta (3)` ) ( `Tartufo (3)` ) ). ENDMETHOD. ENDCLASS. CLASS desserts_vegan DEFINITION INHERITING FROM desserts. PUBLIC SECTION. METHODS get_desserts REDEFINITION. ENDCLASS. CLASS desserts_vegan IMPLEMENTATION. METHOD get_desserts. desserts = VALUE #( ( `Fruit sorbet (3)` ) ( `Almond milk vanilla pudding (3)` ) ( `Apple crumble (3)` ) ). ENDMETHOD. ENDCLASS. CLASS desserts_seafood DEFINITION INHERITING FROM desserts. PUBLIC SECTION. METHODS get_desserts REDEFINITION. ENDCLASS. CLASS desserts_seafood IMPLEMENTATION. METHOD get_desserts. desserts = VALUE #( ( `Lemon sorbet (3)` ) ( `Cheesecake (3)` ) ( `Chocolate mousse (3)` ) ). ENDMETHOD. ENDCLASS. *&---------------------------------------------------------------------* *& Abstract factory *&---------------------------------------------------------------------* CLASS menu_factory DEFINITION ABSTRACT. PUBLIC SECTION. TYPES: BEGIN OF ENUM menu_variant, italian, seafood, vegan, END OF ENUM menu_variant. METHODS: create_starters ABSTRACT RETURNING VALUE(starters_ref) TYPE REF TO starters, create_main_dishes ABSTRACT RETURNING VALUE(main_dishes_ref) TYPE REF TO main_dishes, create_desserts ABSTRACT RETURNING VALUE(desserts_ref) TYPE REF TO desserts. ENDCLASS. *&---------------------------------------------------------------------* *& Concrete factories *&---------------------------------------------------------------------* CLASS italian_menu_creator DEFINITION INHERITING FROM menu_factory. PUBLIC SECTION. METHODS: create_starters REDEFINITION, create_main_dishes REDEFINITION, create_desserts REDEFINITION. ENDCLASS. CLASS italian_menu_creator IMPLEMENTATION. METHOD create_starters. starters_ref = NEW starters_italian( ). ENDMETHOD. METHOD create_main_dishes. main_dishes_ref = NEW main_dishes_italian( ). ENDMETHOD. METHOD create_desserts. desserts_ref = NEW desserts_italian( ). ENDMETHOD. ENDCLASS. CLASS seafood_menu_creator DEFINITION INHERITING FROM menu_factory. PUBLIC SECTION. METHODS: create_starters REDEFINITION, create_main_dishes REDEFINITION, create_desserts REDEFINITION. ENDCLASS. CLASS seafood_menu_creator IMPLEMENTATION. METHOD create_starters. starters_ref = NEW starters_seafood( ). ENDMETHOD. METHOD create_main_dishes. main_dishes_ref = NEW main_dishes_seafood( ). ENDMETHOD. METHOD create_desserts. desserts_ref = NEW desserts_seafood( ). ENDMETHOD. ENDCLASS. CLASS vegan_menu_creator DEFINITION INHERITING FROM menu_factory. PUBLIC SECTION. METHODS: create_starters REDEFINITION, create_main_dishes REDEFINITION, create_desserts REDEFINITION. ENDCLASS. CLASS vegan_menu_creator IMPLEMENTATION. METHOD create_starters. starters_ref = NEW starters_vegan( ). ENDMETHOD. METHOD create_main_dishes. main_dishes_ref = NEW main_dishes_vegan( ). ENDMETHOD. METHOD create_desserts. desserts_ref = NEW desserts_vegan( ). ENDMETHOD. ENDCLASS. *&---------------------------------------------------------------------* *& Client *&---------------------------------------------------------------------* CLASS menu_provider DEFINITION. PUBLIC SECTION. METHODS: constructor IMPORTING factory TYPE REF TO menu_factory, create_menu RETURNING VALUE(menu) TYPE string_table. PRIVATE SECTION. DATA factory TYPE REF TO menu_factory. DATA starters_factory TYPE REF TO starters. DATA main_dishes_factory TYPE REF TO main_dishes. DATA desserts_factory TYPE REF TO desserts. ENDCLASS. CLASS menu_provider IMPLEMENTATION. METHOD create_menu. "The more detailed out code lines are to emphasize that this class deals "with references to abstract types. Appending the lines may also "be achieved with fewer lines of code, as commented out below. starters_factory = factory->create_starters( ). main_dishes_factory = factory->create_main_dishes( ). desserts_factory = factory->create_desserts( ). DATA(starters_for_menu) = starters_factory->get_starters( ). DATA(main_dishes_for_menu) = main_dishes_factory->get_main_dishes( ). DATA(desserts_for_menu) = desserts_factory->get_desserts( ). APPEND LINES OF starters_for_menu TO menu. APPEND LINES OF main_dishes_for_menu TO menu. APPEND LINES OF desserts_for_menu TO menu. "APPEND LINES OF factory->create_starters( )->get_starters( ) TO menu. "APPEND LINES OF factory->create_main_dishes( )->get_main_dishes( ) TO menu. "APPEND LINES OF factory->create_desserts( )->get_desserts( ) TO menu. ENDMETHOD. METHOD constructor. me->factory = factory. ENDMETHOD. ENDCLASS. "Helper class CLASS customer_order DEFINITION CREATE PRIVATE. PUBLIC SECTION. CLASS-METHODS place_order IMPORTING menu_variant TYPE menu_factory=>menu_variant RETURNING VALUE(factory) TYPE REF TO menu_factory. ENDCLASS. CLASS customer_order IMPLEMENTATION. METHOD place_order. CASE menu_variant. WHEN menu_factory=>italian. factory = NEW italian_menu_creator( ). WHEN menu_factory=>seafood. factory = NEW seafood_menu_creator( ). WHEN menu_factory=>vegan. factory = NEW vegan_menu_creator( ). ENDCASE. ENDMETHOD. ENDCLASS. ``` |
| Class include | Code |
| Global class | ``` abap CLASS zcl_demo_abap DEFINITION PUBLIC FINAL CREATE PUBLIC . PUBLIC SECTION. INTERFACES if_oo_adt_classrun. PROTECTED SECTION. PRIVATE SECTION. ENDCLASS. CLASS zcl_demo_abap IMPLEMENTATION. METHOD if_oo_adt_classrun~main. *&---------------------------------------------------------------------* *& Example 1 *&---------------------------------------------------------------------* "Adding strings "Retrieving the resulting string using the attribute 'str' DATA(str1) = lcl_string=>string( `Lorem` )->add( ` ` )->add( `ipsum` )->str. "Instead of extra method calls using the reference variable DATA(str1b_ref) = lcl_string=>string( `Lorem` ). str1b_ref->add( ` ` ). str1b_ref->add( `ipsum` ). DATA(str1b) = str1b_ref->str. "Retrieving the resulting string using the method 'get_string' DATA(str2) = lcl_string=>string( `Lorem` )->add( ` ` )->add( `ipsum` )->add( ` ` )->add( `dolor` )->add( ` ` )->add( `sit` )->add( ` ` )->add( `amet` )->get_string( ). "Preceding strings DATA(str3) = lcl_string=>string( `world` )->precede( ` ` )->precede( `Hello` )->str. DATA(str4) = lcl_string=>string( `B` )->add( `A` )->precede( `A` )->add( `P` )->str. "Splitting into string table DATA(tab1) = lcl_string=>string( `Lorem` )->add( `#` )->add( `ipsum` )->add( `#` )->add( `dolor` )->add( `#` )->add( `sit` )->add( `#` )->add( `amet` )->split_into_table( `#` ). DATA(tab2) = lcl_string=>string( `Lorem` )->add( ` ` )->add( `ipsum` )->split_into_table( ` ` ). "Replacements DATA(str5) = lcl_string=>string( `Lorem#ipsum#dolor#sit#amet` )->replace_all( sub = `#` with = ` ` )->str. DATA(str6) = lcl_string=>string( `Lorem#ipsum#dolor#sit#amet` )->replace_occ( sub = `#` with = ` ` occ = 1 )->str. DATA(str7) = lcl_string=>string( `Lorem#ipsum#dolor#sit#amet` )->replace_occ( sub = `#` with = ` ` occ = 2 )->str. DATA(str8) = lcl_string=>string( `Lorem#ipsum#dolor#sit#amet` )->replace_occ( sub = `#` with = ` ` occ = -2 )->str. DATA(tab3) = lcl_string=>string( `hello` )->add( `#` )->add( `world` )->replace_all( sub = `#` with = `,` )->split_into_table( `,` ). "Transforming to lowercase and uppercase DATA(str9) = lcl_string=>string( `ab` )->add( `ap` )->uppercase( )->str. DATA(str10) = lcl_string=>string( `AP` )->precede( `AB` )->lowercase( )->str. DATA(str11) = lcl_string=>string( `AB` )->lowercase( )->add( `ap` )->uppercase( )->str. "First lowercasing overridden "Reversing string DATA(str12) = lcl_string=>string( `OLL` )->add( `AH` )->lowercase( )->reverse_string( )->str. "Inserting string DATA(str13) = lcl_string=>string( `abcghi` )->insert_string( string = `def` off = 3 )->str. DATA(str14) = lcl_string=>string( `vwxyz` )->insert_string( string = `stu` off = 0 )->str. "Removing spaces "All spaces DATA(str15) = lcl_string=>string( ` a b c` )->add( ` d e f gh i ` )->remove_all_spaces( )->str. "Leading and trailing spaces DATA(str16) = lcl_string=>string( ` ab c d e f g h i ` )->remove_leading_trailing_spaces( )->str. DATA(str17) = lcl_string=>string( `abc ` )->remove_leading_trailing_spaces( )->add( `def` )->str. "Displaying results in the console out->write( data = str1 name = `str1` ). out->write( |\n| ). out->write( data = str1b name = `str1b` ). out->write( |\n| ). out->write( data = str2 name = `str2` ). out->write( |\n| ). out->write( data = str3 name = `str3` ). out->write( |\n| ). out->write( data = str4 name = `str4` ). out->write( |\n| ). out->write( data = tab1 name = `tab1` ). out->write( |\n| ). out->write( data = tab2 name = `tab2` ). out->write( |\n| ). out->write( data = str5 name = `str5` ). out->write( |\n| ). out->write( data = str6 name = `str6` ). out->write( |\n| ). out->write( data = str7 name = `str7` ). out->write( |\n| ). out->write( data = str8 name = `str8` ). out->write( |\n| ). out->write( data = tab3 name = `tab3` ). out->write( |\n| ). out->write( data = str9 name = `str9` ). out->write( |\n| ). out->write( data = str10 name = `str10` ). out->write( |\n| ). out->write( data = str11 name = `str11` ). out->write( |\n| ). out->write( data = str12 name = `str12` ). out->write( |\n| ). out->write( data = str13 name = `str13` ). out->write( |\n| ). out->write( data = str14 name = `str14` ). out->write( |\n| ). out->write( data = str15 name = `str15` ). out->write( |\n| ). out->write( data = str16 name = `str16` ). out->write( |\n| ). out->write( data = str17 name = `str17` ). out->write( |\n| ). ********************************************************************** *&---------------------------------------------------------------------* *& Example 2 *&---------------------------------------------------------------------* DATA(calc1) = NEW lcl_calc( 1 )->plus( 2 )->get_result( ). DATA(calc2) = NEW lcl_calc( 1 )->minus( 2 )->get_result( ). DATA(calc3) = NEW lcl_calc( 5 )->plus( 2 )->minus( 1 )->multiply( 3 )->get_result( ). DATA(calc4) = NEW lcl_calc( 10 )->multiply( 10 )->divide( 2 )->get_result( ). DATA(calc5) = NEW lcl_calc( 0 )->plus( 1 )->divide( 5 )->get_result( ). DATA(calc6) = NEW lcl_calc( '1.2' )->plus( '1.4' )->minus( '0.1' )->multiply( '2.5' )->divide( 2 )->get_result( ). "Arithmetic errors are just ignored in the example DATA(calc7) = NEW lcl_calc( 1 )->divide( 0 )->plus( 1 )->get_result( ). "Method chaining with a standalone statements NEW lcl_calc( 1 )->plus( 2 )->multiply( 5 )->minus( 5 )->divide( 2 )->get_result( RECEIVING result = DATA(calc8) ). IF NEW lcl_calc( 1 )->plus( 2 )->minus( 3 )->plus( 4 )->minus( 5 )->get_result( ) <= 0. DATA(if_statement) = `The result is equal to or lower than 0`. ELSE. if_statement = `The result is greater than 0`. ENDIF. out->write( data = calc1 name = `calc1` ). out->write( |\n| ). out->write( data = calc2 name = `calc2` ). out->write( |\n| ). out->write( data = calc3 name = `calc3` ). out->write( |\n| ). out->write( data = calc3 name = `calc3` ). out->write( |\n| ). out->write( data = calc4 name = `calc4` ). out->write( |\n| ). out->write( data = calc5 name = `calc5` ). out->write( |\n| ). out->write( data = calc6 name = `calc6` ). out->write( |\n| ). out->write( data = calc7 name = `calc7` ). out->write( |\n| ). out->write( data = calc8 name = `calc8` ). out->write( |\n| ). out->write( data = if_statement name = `if_statement` ). ENDMETHOD. ENDCLASS. ``` |
| CCIMP include (Local Types tab in ADT) | ``` abap *&---------------------------------------------------------------------* *& Example 1 *&---------------------------------------------------------------------* INTERFACE lif_string_processing. DATA str TYPE string READ-ONLY. METHODS add IMPORTING string TYPE clike RETURNING VALUE(ref) TYPE REF TO lif_string_processing. METHODS precede IMPORTING string TYPE clike RETURNING VALUE(ref) TYPE REF TO lif_string_processing. METHODS replace_all IMPORTING sub TYPE clike with TYPE clike RETURNING VALUE(ref) TYPE REF TO lif_string_processing. METHODS replace_occ IMPORTING sub TYPE clike with TYPE clike occ TYPE i DEFAULT 1 RETURNING VALUE(ref) TYPE REF TO lif_string_processing. METHODS lowercase RETURNING VALUE(ref) TYPE REF TO lif_string_processing. METHODS uppercase RETURNING VALUE(ref) TYPE REF TO lif_string_processing. METHODS remove_leading_trailing_spaces RETURNING VALUE(ref) TYPE REF TO lif_string_processing. METHODS remove_all_spaces RETURNING VALUE(ref) TYPE REF TO lif_string_processing. METHODS reverse_string RETURNING VALUE(ref) TYPE REF TO lif_string_processing. METHODS insert_string IMPORTING string TYPE clike off TYPE i RETURNING VALUE(ref) TYPE REF TO lif_string_processing. METHODS get_string RETURNING VALUE(str) TYPE string. METHODS split_into_table IMPORTING split_at TYPE clike RETURNING VALUE(tab) TYPE string_table. ENDINTERFACE. CLASS lcl_string DEFINITION DEFERRED. CLASS lcl_string_processing DEFINITION FINAL CREATE PRIVATE FRIENDS lcl_string. PUBLIC SECTION. INTERFACES lif_string_processing. ALIASES: add FOR lif_string_processing~add, get_string FOR lif_string_processing~get_string, insert_string FOR lif_string_processing~insert_string, precede FOR lif_string_processing~precede, remove_all_spaces FOR lif_string_processing~remove_all_spaces, remove_leading_trailing_spaces FOR lif_string_processing~remove_leading_trailing_spaces, replace_all FOR lif_string_processing~replace_all, replace_occ FOR lif_string_processing~replace_occ, reverse_string FOR lif_string_processing~reverse_string, split_into_table FOR lif_string_processing~split_into_table, lowercase FOR lif_string_processing~lowercase, uppercase FOR lif_string_processing~uppercase. PROTECTED SECTION. PRIVATE SECTION. ALIASES string_content FOR lif_string_processing~str. METHODS constructor IMPORTING content TYPE string. DATA oref TYPE REF TO lcl_string_processing. ENDCLASS. CLASS lcl_string_processing IMPLEMENTATION. METHOD add. oref->string_content &&= string. ref = oref. ENDMETHOD. METHOD get_string. str = oref->string_content. ENDMETHOD. METHOD insert_string. TRY. oref->string_content = insert( val = oref->string_content sub = string off = off ). CATCH cx_sy_range_out_of_bounds. ENDTRY. ref = oref. ENDMETHOD. METHOD precede. oref->string_content = string && oref->string_content. ref = oref. ENDMETHOD. METHOD remove_all_spaces. oref->string_content = condense( val = oref->string_content to = `` ). ref = oref. ENDMETHOD. METHOD remove_leading_trailing_spaces. oref->string_content = condense( val = oref->string_content from = `` ). ref = oref. ENDMETHOD. METHOD replace_all. oref->string_content = replace( val = oref->string_content sub = sub with = with occ = 0 ). ref = oref. ENDMETHOD. METHOD replace_occ. oref->string_content = replace( val = oref->string_content sub = sub with = with occ = occ ). ref = oref. ENDMETHOD. METHOD reverse_string. oref->string_content = reverse( oref->string_content ). ref = oref. ENDMETHOD. METHOD split_into_table. SPLIT oref->string_content AT split_at INTO TABLE tab. ENDMETHOD. METHOD lowercase. oref->string_content = to_lower( oref->string_content ). ref = oref. ENDMETHOD. METHOD uppercase. oref->string_content = to_upper( oref->string_content ). ref = oref. ENDMETHOD. METHOD constructor. string_content = content. oref = me. ENDMETHOD. ENDCLASS. CLASS lcl_string DEFINITION FINAL CREATE PRIVATE FRIENDS lcl_string_processing. PUBLIC SECTION. CLASS-METHODS string IMPORTING string TYPE clike RETURNING VALUE(ref) TYPE REF TO lif_string_processing. PROTECTED SECTION. PRIVATE SECTION. ENDCLASS. CLASS lcl_string IMPLEMENTATION. METHOD string. ref = NEW lcl_string_processing( string ). ENDMETHOD. ENDCLASS. ********************************************************************** *&---------------------------------------------------------------------* *& Example 2 *&---------------------------------------------------------------------* CLASS lcl_calc DEFINITION FINAL CREATE PUBLIC. PUBLIC SECTION. METHODS constructor IMPORTING num TYPE decfloat34. METHODS plus IMPORTING num TYPE decfloat34 RETURNING VALUE(ref) TYPE REF TO lcl_calc. METHODS minus IMPORTING num TYPE decfloat34 RETURNING VALUE(ref) TYPE REF TO lcl_calc. METHODS multiply IMPORTING num TYPE decfloat34 RETURNING VALUE(ref) TYPE REF TO lcl_calc. METHODS divide IMPORTING num TYPE decfloat34 RETURNING VALUE(ref) TYPE REF TO lcl_calc. METHODS get_result RETURNING VALUE(result) TYPE decfloat34. PROTECTED SECTION. PRIVATE SECTION. DATA number TYPE decfloat34. ENDCLASS. CLASS lcl_calc IMPLEMENTATION. METHOD constructor. number = num. ENDMETHOD. METHOD divide. TRY. number /= num. CATCH cx_sy_arithmetic_error. ENDTRY. ref = me. ENDMETHOD. METHOD minus. TRY. number -= num. CATCH cx_sy_arithmetic_error. ENDTRY. ref = me. ENDMETHOD. METHOD multiply. TRY. number *= num. CATCH cx_sy_arithmetic_error. ENDTRY. ref = me. ENDMETHOD. METHOD plus. TRY. number += num. CATCH cx_sy_arithmetic_error. ENDTRY. ref = me. ENDMETHOD. METHOD get_result. result = number. ENDMETHOD. ENDCLASS. ``` |
| Class include | Code |
| Global class | ``` abap CLASS zcl_demo_abap DEFINITION PUBLIC FINAL CREATE PUBLIC . PUBLIC SECTION. INTERFACES if_oo_adt_classrun. PROTECTED SECTION. PRIVATE SECTION. ENDCLASS. CLASS zcl_demo_abap IMPLEMENTATION. METHOD if_oo_adt_classrun~main. "Saying hello in English DATA(oref_en) = lcl_hello_factory=>create_hello( lif_hello=>en ). DATA(hello_en) = oref_en->say_hello( ). out->write( hello_en ). "Saying hello in French DATA(oref_fr) = lcl_hello_factory=>create_hello( lif_hello=>fr ). DATA(hello_fr) = oref_fr->say_hello( ). out->write( hello_fr ). "Saying hello in Italian DATA(oref_it) = lcl_hello_factory=>create_hello( lif_hello=>it ). DATA(hello_it) = oref_it->say_hello( ). out->write( hello_it ). "Saying hello in Spanish DATA(oref_es) = lcl_hello_factory=>create_hello( lif_hello=>es ). DATA(hello_es) = oref_es->say_hello( ). out->write( hello_es ). "Saying hello in German "See the local class implementation. This method call demonstrates the adapter since "the required data is originally available in a non-conform way ('Hallo' is "available as xstring, coming from a different API that does not implement the same "interface as the other classes). The adapter class (called when creating the instance "in the factory method) integrates the non-conform API and transforms the content. DATA(oref_de) = lcl_hello_factory=>create_hello( lif_hello=>de ). DATA(hello_de) = oref_de->say_hello( ). out->write( hello_de ). "Default hello DATA(oref_default) = lcl_hello_factory=>create_hello( lif_hello=>init ). DATA(hello_default) = oref_default->say_hello( ). out->write( hello_default ). ENDMETHOD. ENDCLASS. ``` |
| CCIMP include (Local Types tab in ADT) | ``` abap INTERFACE lif_hello. TYPES: basetype TYPE i, BEGIN OF ENUM enum_langu BASE TYPE basetype, init VALUE IS INITIAL, en VALUE 1, fr VALUE 2, it VALUE 3, es VALUE 4, de VALUE 5, END OF ENUM enum_langu. METHODS say_hello RETURNING VALUE(hi) TYPE string. ENDINTERFACE. CLASS lcl_en DEFINITION FINAL CREATE PUBLIC. PUBLIC SECTION. INTERFACES lif_hello. PROTECTED SECTION. PRIVATE SECTION. ENDCLASS. CLASS lcl_en IMPLEMENTATION. METHOD lif_hello~say_hello. hi = `Hi`. ENDMETHOD. ENDCLASS. CLASS lcl_fr DEFINITION FINAL CREATE PUBLIC. PUBLIC SECTION. INTERFACES lif_hello. PROTECTED SECTION. PRIVATE SECTION. ENDCLASS. CLASS lcl_fr IMPLEMENTATION. METHOD lif_hello~say_hello. hi = `Salut`. ENDMETHOD. ENDCLASS. CLASS lcl_it DEFINITION FINAL CREATE PUBLIC. PUBLIC SECTION. INTERFACES lif_hello. PROTECTED SECTION. PRIVATE SECTION. ENDCLASS. CLASS lcl_it IMPLEMENTATION. METHOD lif_hello~say_hello. hi = `Ciao`. ENDMETHOD. ENDCLASS. CLASS lcl_es DEFINITION FINAL CREATE PUBLIC. PUBLIC SECTION. INTERFACES lif_hello. PROTECTED SECTION. PRIVATE SECTION. ENDCLASS. CLASS lcl_es IMPLEMENTATION. METHOD lif_hello~say_hello. hi = `Hola`. ENDMETHOD. ENDCLASS. ********************************************************************** "Class that does not implement the lif_hello interface "The assumption is that functionality of the API is reused and integrated "into the exsisting API. The non-compatible type is converted using an "adapter class. INTERFACE lif_hello_as_xstring. METHODS xstring_hello RETURNING VALUE(hi) TYPE xstring. ENDINTERFACE. CLASS lcl_de_xstring DEFINITION FINAL CREATE PUBLIC. PUBLIC SECTION. INTERFACES lif_hello_as_xstring. PROTECTED SECTION. PRIVATE SECTION. ENDCLASS. CLASS lcl_de_xstring IMPLEMENTATION. METHOD lif_hello_as_xstring~xstring_hello. hi = CONV xstring( `48616C6C6F` ). ENDMETHOD. ENDCLASS. ********************************************************************** "Adapter class CLASS lcl_de_adapter DEFINITION. PUBLIC SECTION. INTERFACES: lif_hello. ENDCLASS. CLASS lcl_de_adapter IMPLEMENTATION. METHOD lif_hello~say_hello. DATA(oref) = NEW lcl_de_xstring( ). DATA(hello_as_xstring) = oref->lif_hello_as_xstring~xstring_hello( ). hi = cl_abap_conv_codepage=>create_in( )->convert( hello_as_xstring ). ENDMETHOD. ENDCLASS. ********************************************************************** "Class containing a factory method CLASS lcl_hello_factory DEFINITION FINAL CREATE PRIVATE. PUBLIC SECTION. CLASS-METHODS create_hello IMPORTING language TYPE lif_hello=>enum_langu RETURNING VALUE(hello) TYPE REF TO lif_hello. PROTECTED SECTION. PRIVATE SECTION. ENDCLASS. CLASS lcl_hello_factory IMPLEMENTATION. METHOD create_hello. hello = SWITCH #( language WHEN lif_hello=>en THEN NEW lcl_en( ) WHEN lif_hello=>fr THEN NEW lcl_fr( ) WHEN lif_hello=>it THEN NEW lcl_it( ) WHEN lif_hello=>es THEN NEW lcl_es( ) "Calling the method in the adapter class WHEN lif_hello=>de THEN NEW lcl_de_adapter( ) "E.g. raising an exception or returning a default object ELSE NEW lcl_en( ) ). ENDMETHOD. ENDCLASS. ``` |
| Class include | Code |
| Global class |
``` abap
"! ABAP example demonstrating the builder design pattern
"! See the disclaimer in the ABAP cheat sheet repository's readme file.
CLASS zcl_demo_abap DEFINITION
PUBLIC
FINAL
CREATE PUBLIC .
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun.
CLASS-METHODS get_table_info IMPORTING itab TYPE ANY TABLE RETURNING VALUE(info) TYPE string_table.
PROTECTED SECTION.
PRIVATE SECTION.
ENDCLASS.
CLASS zcl_demo_abap IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
"Creating a string table that includes type names
"The entries include database table, CDS entity names of the ABAP cheat sheet repository.
"Plus, elementary types (built-in ABAP types) and a non-existent type are included.
DATA(type_names) = VALUE string_table(
( `ZDEMO_ABAP_CARR` )
( `ZDEMO_ABAP_FLI` )
( `ZDEMO_ABAP_CARR_VE` )
( `ZDEMO_ABAP_ABSTRACT_ENT` )
"Elementary types
( `STRING` )
( `UTCLONG` )
"Non-existent type
( `TYPE_THAT_DOES_NOT_EXIST` ) ).
out->write( `1) Creating standard tables with non-unique primary table keys` ).
out->write( |\n| ).
"Specifying no key components, using default ones
LOOP AT type_names INTO DATA(name).
DATA(oref) = lcl_itab_provider=>create_itab(
type_name = name
table_kind = lcl_itab_provider=>standard_w_nonunique_pr_key
table_entry_count = 10 ).
out->write( |------------- Table with line type { oref->type_name } -------------| ).
out->write( |\n| ).
IF oref->type_exists = abap_true.
"The example is designed to retrieve Table type informationrmation so as to display
"information such type and table keys of the internal table.
DATA(info) = get_table_info( oref->itab->* ).
out->write( `Table type information:` ).
out->write( info ).
out->write( |\n| ).
out->write( oref->itab->* ).
out->write( |\n| ).
ELSE.
out->write( `Type does not exist. Internal table not created.` ).
out->write( |\n| ).
ENDIF.
ENDLOOP.
out->write( `------------- Key components explicitly specified -------------` ).
out->write( |\n| ).
"Key components explicitly specified (including a non-existent component name that is ignored)
DATA(oref_key_specified) = lcl_itab_provider=>create_itab(
type_name = `ZDEMO_ABAP_CARR`
table_kind = lcl_itab_provider=>standard_w_nonunique_pr_key
key_components = VALUE #( ( `CARRID` ) ( `CARRNAME` ) ( `FALSE_COMPONENT` ) )
table_entry_count = 3 ).
out->write( `------------- Table with line type ZDEMO_ABAP_CARR -------------` ).
IF oref_key_specified->type_exists = abap_true.
info = get_table_info( oref_key_specified->itab->* ).
out->write( `Table type information:` ).
out->write( info ).
out->write( |\n| ).
out->write( oref_key_specified->itab->* ).
out->write( |\n| ).
ELSE.
out->write( `Type does not exist. Internal table not created.` ).
out->write( |\n| ).
ENDIF.
out->write( repeat( val = `*` occ = 100 ) ).
out->write( |\n| ).
**********************************************************************
out->write( `2) Creating standard tables with empty key` ).
out->write( |\n| ).
type_names = VALUE string_table(
( `ZDEMO_ABAP_FLSCH` )
( `D` ) ).
LOOP AT type_names INTO name.
DATA(oref_empty_key) = lcl_itab_provider=>create_itab(
type_name = name
table_kind = lcl_itab_provider=>standard_w_empty_key
"Specified key components are ignored in the example
"key_components = VALUE #( ( `CARRID` ) ( `CARRNAME` ) )
table_entry_count = 3 ).
out->write( |------------- Table with line type { oref_empty_key->type_name } -------------| ).
out->write( |\n| ).
IF oref_empty_key->type_exists = abap_true.
info = get_table_info( oref_empty_key->itab->* ).
out->write( `Table type information:` ).
out->write( info ).
out->write( |\n| ).
out->write( oref_empty_key->itab->* ).
out->write( |\n| ).
ELSE.
out->write( `Type does not exist. Internal table not created.` ).
out->write( |\n| ).
ENDIF.
ENDLOOP.
out->write( repeat( val = `*` occ = 100 ) ).
out->write( |\n| ).
**********************************************************************
out->write( `3) Creating sorted tables with unique primary keys` ).
out->write( |\n| ).
type_names = VALUE string_table(
( `ZDEMO_ABAP_FLI` )
( `ZDEMO_ABAP_TAB1` )
( `T` ) ).
LOOP AT type_names INTO name.
DATA(oref_sorted) = lcl_itab_provider=>create_itab(
type_name = name
table_kind = lcl_itab_provider=>sorted_w_unique_pr_key
table_entry_count = 3 ).
out->write( |------------- Table with line type { oref_sorted->type_name } -------------| ).
out->write( |\n| ).
IF oref_sorted->type_exists = abap_true.
info = get_table_info( oref_sorted->itab->* ).
out->write( `Table type information:` ).
out->write( info ).
out->write( |\n| ).
out->write( oref_sorted->itab->* ).
out->write( |\n| ).
ELSE.
out->write( `Type does not exist. Internal table not created.` ).
out->write( |\n| ).
ENDIF.
ENDLOOP.
out->write( repeat( val = `*` occ = 100 ) ).
out->write( |\n| ).
**********************************************************************
out->write( `4) Creating hashed tables with unique primary keys` ).
out->write( |\n| ).
type_names = VALUE string_table(
( `ZDEMO_ABAP_CARR` )
( `ZDEMO_ABAP_TAB2` )
( `I` ) ).
LOOP AT type_names INTO name.
DATA(oref_hashed) = lcl_itab_provider=>create_itab(
type_name = name
table_kind = lcl_itab_provider=>hashed_w_unique_pr_key
table_entry_count = 3 ).
out->write( |------------- Table with line type { oref_hashed->type_name } -------------| ).
out->write( |\n| ).
IF oref_hashed->type_exists = abap_true.
info = get_table_info( oref_hashed->itab->* ).
out->write( `Table type information:` ).
out->write( info ).
out->write( |\n| ).
out->write( oref_hashed->itab->* ).
out->write( |\n| ).
ELSE.
out->write( `Type does not exist. Internal table not created.` ).
out->write( |\n| ).
ENDIF.
ENDLOOP.
out->write( repeat( val = `*` occ = 100 ) ).
out->write( |\n| ).
**********************************************************************
out->write( `5) Populating internal tables with random data` ).
out->write( |\n| ).
"Demo internal tables to be filled
DATA it_std1 TYPE TABLE OF zdemo_abap_carr WITH EMPTY KEY.
DATA it_std2 TYPE string_table.
DATA it_std3 TYPE TABLE OF i.
TYPES: BEGIN OF various_types,
c1 TYPE c LENGTH 1,
c5 TYPE c LENGTH 5,
c10 TYPE c LENGTH 10,
str TYPE string,
int TYPE i,
f TYPE f,
dec16 TYPE decfloat16,
dec34 TYPE decfloat34,
i8 TYPE int8,
n5 TYPE n LENGTH 5,
time TYPE t,
date TYPE d,
timestamp TYPE utclong,
x1 TYPE x LENGTH 1,
x5 TYPE x LENGTH 5,
xstr TYPE xstring,
pl2d1 TYPE p LENGTH 2 DECIMALS 1,
pl3d2 TYPE p LENGTH 3 DECIMALS 2,
pl4d3 TYPE p LENGTH 4 DECIMALS 3,
pl5d4 TYPE p LENGTH 5 DECIMALS 4,
pl6d5 TYPE p LENGTH 6 DECIMALS 5,
pl7d6 TYPE p LENGTH 7 DECIMALS 6,
pl8d7 TYPE p LENGTH 8 DECIMALS 7,
pl9d8 TYPE p LENGTH 9 DECIMALS 8,
pl10d9 TYPE p LENGTH 10 DECIMALS 9,
pl11d10 TYPE p LENGTH 11 DECIMALS 10,
pl12d11 TYPE p LENGTH 12 DECIMALS 11,
pl13d12 TYPE p LENGTH 13 DECIMALS 12,
pl14d13 TYPE p LENGTH 14 DECIMALS 13,
pl15d14 TYPE p LENGTH 15 DECIMALS 14,
END OF various_types.
DATA it_std4 TYPE TABLE OF various_types WITH EMPTY KEY.
"Sorted tables
DATA it_sorted1 TYPE SORTED TABLE OF zdemo_abap_flsch WITH NON-UNIQUE KEY primary_key COMPONENTS carrid connid cityfrom.
DATA it_sorted2 TYPE SORTED TABLE OF zdemo_abap_fli WITH UNIQUE KEY carrid connid.
DATA it_sorted3 TYPE SORTED TABLE OF utclong WITH NON-UNIQUE KEY table_line.
"Hashed tables
DATA it_hashed1 TYPE HASHED TABLE OF zdemo_abap_flsch WITH UNIQUE KEY primary_key COMPONENTS carrid connid.
TYPES n5 TYPE n LENGTH 5.
DATA it_hashed2 TYPE HASHED TABLE OF n5 WITH UNIQUE KEY primary_key COMPONENTS table_line.
TYPES table_refs TYPE TABLE OF REF TO data WITH EMPTY KEY.
DATA(itab_refs) = VALUE table_refs(
( REF #( it_std1 ) )
( REF #( it_std2 ) )
( REF #( it_std3 ) )
( REF #( it_std4 ) )
( REF #( it_sorted1 ) )
( REF #( it_sorted2 ) )
( REF #( it_sorted3 ) )
( REF #( it_hashed1 ) )
( REF #( it_hashed2 ) ) ).
LOOP AT itab_refs INTO DATA(ref).
DATA(tabix) = sy-tabix.
DATA(oref_populate_itab) = lcl_itab_provider=>populate_itab(
itab = ref->*
table_entry_count = 3
).
out->write( |------------- Internal table { tabix } -------------| ).
out->write( |\n| ).
info = get_table_info( oref_populate_itab->itab->* ).
out->write( `Table type information:` ).
out->write( info ).
out->write( |\n| ).
out->write( oref_populate_itab->itab->* ).
out->write( |\n| ).
ENDLOOP.
out->write( repeat( val = `*` occ = 100 ) ).
out->write( |\n| ).
**********************************************************************
out->write( `6) Other line types` ).
out->write( |\n| ).
"Other line types not supported in the example
*DATA(oref_not_working) = lcl_itab_provider=>populate_itab(
* itab = itab_refs
* table_entry_count = 3 ).
"Deep/nested line types are not supported
"These components remain initial.
TYPES: BEGIN OF deep_type,
flag TYPE abap_boolean,
c5 TYPE c LENGTH 5,
strtab TYPE string_table,
struc TYPE zdemo_abap_carr,
END OF deep_type.
DATA deep_itab TYPE TABLE OF deep_type WITH EMPTY KEY.
DATA(oref_deep) = lcl_itab_provider=>populate_itab(
itab = deep_itab
table_entry_count = 3 ).
out->write( oref_deep->itab->* ).
out->write( |\n| ).
out->write( repeat( val = `*` occ = 100 ) ).
out->write( |\n| ).
**********************************************************************
out->write( `7) Exploring the random value creation methods` ).
out->write( |\n| ).
out->write( `---------------- Getting random strings ----------------` ).
DO 5 TIMES.
DATA(str) = lcl_itab_builder=>get_random_string( sy-index ).
out->write( str ).
ENDDO.
out->write( `---------------- Getting random number sequences ----------------` ).
DO 5 TIMES.
DATA(number_set) = lcl_itab_builder=>get_random_number_sequence( sy-index ).
out->write( number_set ).
ENDDO.
out->write( `---------------- Getting random packed numbers ----------------` ).
DO 15 TIMES.
DATA(random_p) = lcl_itab_builder=>get_random_p(
length = 8
decimals = sy-index - 1 ).
out->write( random_p->* ).
ENDDO.
out->write( `---------------- Getting random dates ----------------` ).
DO 5 TIMES.
DATA(random_d) = lcl_itab_builder=>get_random_d( ).
out->write( random_d ).
ENDDO.
out->write( `---------------- Getting random times ----------------` ).
DO 5 TIMES.
DATA(random_t) = lcl_itab_builder=>get_random_t( ).
out->write( random_t ).
ENDDO.
out->write( `---------------- Getting random UTC timestamps ----------------` ).
DO 5 TIMES.
DATA(random_utc) = lcl_itab_builder=>get_random_utclong( ).
out->write( random_utc ).
ENDDO.
out->write( `---------------- Getting random data objects of type decfloat16 ----------------` ).
DO 5 TIMES.
DATA(random_dec16) = lcl_itab_builder=>get_random_dec16( ).
out->write( random_dec16 ).
ENDDO.
out->write( `---------------- Getting random data objects of type decfloat34 ----------------` ).
DO 5 TIMES.
DATA(random_dec34) = lcl_itab_builder=>get_random_dec34( ).
out->write( random_dec34 ).
ENDDO.
out->write( `---------------- Getting random data objects of type f ----------------` ).
DO 5 TIMES.
DATA(random_f) = lcl_itab_builder=>get_random_f( ).
out->write( random_f ).
ENDDO.
out->write( `---------------- Getting random data objects of type x ----------------` ).
DATA(xstr_1) = lcl_itab_builder=>get_random_x( 1 ).
DATA x1 TYPE x LENGTH 1.
x1 = xstr_1.
out->write( x1 ).
DATA(xstr_2) = lcl_itab_builder=>get_random_x( 2 ).
DATA x2 TYPE x LENGTH 2.
x2 = xstr_2.
out->write( x2 ).
DATA(xstr_8) = lcl_itab_builder=>get_random_x( 8 ).
DATA x8 TYPE x LENGTH 8.
x8 = xstr_8.
out->write( x8 ).
out->write( `---------------- Getting random data objects of type xstring ----------------` ).
DATA(xstr_a) = lcl_itab_builder=>get_random_xstring( ).
out->write( xstr_a ).
DATA(xstr_b) = lcl_itab_builder=>get_random_xstring( ).
out->write( xstr_b ).
DATA(xstr_c) = lcl_itab_builder=>get_random_xstring( ).
out->write( xstr_c ).
ENDMETHOD.
METHOD get_table_info.
DATA(tab_type_info) = CAST cl_abap_tabledescr( cl_abap_typedescr=>describe_by_data( itab ) ).
"Getting the table kind
"For the constant values of type abap_tablekind, see cl_abap_tabledescr. For example, 'S'
"stands for a standard table.
DATA(tab_table_kind) = tab_type_info->table_kind.
INSERT |Table kind: { tab_table_kind }| INTO TABLE info.
"Checking if the table has a unique key
DATA(tab_has_unique_key) = tab_type_info->has_unique_key.
INSERT |Has a unique key: "{ tab_has_unique_key }" | &&
|{ COND #( WHEN tab_has_unique_key IS INITIAL THEN `(no unique key)` ) }| INTO TABLE info.
"Returning a table with a description of all table keys, e.g. all components of a key,
"key kind (U, unique, in the example case), information whether the key is the primary
"key etc. For the constant values, see the cl_abap_tabledescr class.
DATA(tab_keys) = tab_type_info->get_keys( ).
INSERT |Table keys: { REDUCE string( INIT str = `` FOR |
| CCIMP include (Local Types tab in ADT) |
``` abap
"Class for the builder
"An abstract class is used as there are more general tasks performed by the subclasses.
"These tasks are implemented in non-abstract methods in the class.
CLASS lcl_itab_builder DEFINITION ABSTRACT CREATE PUBLIC.
PUBLIC SECTION.
DATA type_name TYPE string.
DATA primary_key_components TYPE string_table.
DATA itab TYPE REF TO data.
DATA table_entries_to_create TYPE i.
DATA type_exists TYPE abap_boolean.
DATA components TYPE cl_abap_structdescr=>component_table.
DATA is_elementary_line_type TYPE abap_boolean.
DATA table_type_descr_obj TYPE REF TO cl_abap_tabledescr.
DATA line_type TYPE REF TO cl_abap_datadescr.
"----------------------- Abstract methods -----------------------
METHODS build_type_info ABSTRACT RETURNING VALUE(type_exists) TYPE abap_boolean.
METHODS build_components ABSTRACT.
METHODS build_table_keys ABSTRACT.
METHODS build_table_type ABSTRACT.
METHODS build_data_object ABSTRACT.
METHODS build_random_data ABSTRACT.
"----------------------- Constants used in non-abstract methods -----------------------
CONSTANTS character_set TYPE string VALUE `abcdefghijklmnopqrstuvwxyz0123456789`.
CONSTANTS number_set TYPE string VALUE `0123456789`.
CONSTANTS max_length TYPE i VALUE 10.
CONSTANTS start_date TYPE d VALUE '20250101'.
CONSTANTS start_time TYPE t VALUE '000000'.
CONSTANTS max_table_entry_count TYPE i VALUE 50.
CONSTANTS min_int_value TYPE i VALUE 1.
CONSTANTS max_int_value TYPE i VALUE 100.
CONSTANTS min_int8_value TYPE int8 VALUE 1.
CONSTANTS max_int8_value TYPE int8 VALUE 100.
CONSTANTS min_p_value TYPE p VALUE 0.
CONSTANTS max_p_value TYPE p VALUE 9.
"----------------------- Non-abstract methods used by subclasses -----------------------
"They are intentionally included in the public visibility section for the demo in the
"global class.
METHODS check_type.
METHODS handle_keys.
METHODS handle_components.
METHODS add_table_entries
IMPORTING
VALUE(table_entry_count) TYPE i.
CLASS-METHODS get_random_string
IMPORTING
length TYPE i OPTIONAL
randomize_length TYPE abap_boolean DEFAULT abap_true
PREFERRED PARAMETER length
RETURNING
VALUE(str) TYPE string.
CLASS-METHODS get_random_number_sequence
IMPORTING
length TYPE i OPTIONAL
randomize_length TYPE abap_boolean DEFAULT abap_true
PREFERRED PARAMETER length
RETURNING
VALUE(numbers) TYPE string.
CLASS-METHODS get_random_i
IMPORTING min_value TYPE i DEFAULT min_int_value
max_value TYPE i DEFAULT max_int_value
RETURNING VALUE(number) TYPE i.
CLASS-METHODS get_random_int8
IMPORTING min_value TYPE int8 DEFAULT min_int8_value
max_value TYPE int8 DEFAULT max_int8_value
RETURNING VALUE(number) TYPE i.
CLASS-METHODS get_random_p
IMPORTING length TYPE i
decimals TYPE i
min_value TYPE p DEFAULT min_p_value
max_value TYPE p DEFAULT max_p_value
RETURNING VALUE(packed_number) TYPE REF TO data.
CLASS-METHODS get_random_n
IMPORTING length TYPE i
RETURNING VALUE(random_n) TYPE string.
CLASS-METHODS get_random_d
RETURNING VALUE(random_d) TYPE d.
CLASS-METHODS get_random_t
RETURNING VALUE(random_t) TYPE t.
CLASS-METHODS get_random_utclong
RETURNING VALUE(random_utc) TYPE utclong.
CLASS-METHODS get_random_dec16
RETURNING VALUE(random_dec16) TYPE decfloat16.
CLASS-METHODS get_random_dec34
RETURNING VALUE(random_dec34) TYPE decfloat34.
CLASS-METHODS get_random_f
RETURNING VALUE(random_f) TYPE f.
CLASS-METHODS get_random_x
IMPORTING length TYPE i
RETURNING VALUE(random_x) TYPE xstring.
CLASS-METHODS get_random_xstring
RETURNING VALUE(random_xstring) TYPE xstring.
PROTECTED SECTION.
PRIVATE SECTION.
ENDCLASS.
CLASS lcl_itab_builder IMPLEMENTATION.
METHOD get_random_string.
IF length IS NOT SUPPLIED.
DATA(len) = cl_abap_random_int=>create( seed = cl_abap_random=>seed( )
min = 1
max = max_length )->get_next( ).
ELSE.
IF length NOT BETWEEN 1 AND max_length.
len = max_length.
ELSE.
len = length.
ENDIF.
IF randomize_length = abap_true.
len = cl_abap_random_int=>create( seed = cl_abap_random=>seed( )
min = 1
max = len )->get_next( ).
ENDIF.
ENDIF.
DO len TIMES.
DATA(num) = cl_abap_random_int=>create( seed = cl_abap_random=>seed( )
min = 0
max = strlen( character_set ) - 1 )->get_next( ).
str &&= character_set+num(1).
ENDDO.
ENDMETHOD.
METHOD get_random_number_sequence.
IF length IS NOT SUPPLIED.
DATA(len) = cl_abap_random_int=>create( seed = cl_abap_random=>seed( )
min = 1
max = max_length )->get_next( ).
ELSE.
IF length NOT BETWEEN 1 AND max_length.
len = max_length.
ELSE.
len = length.
ENDIF.
IF randomize_length = abap_true.
len = cl_abap_random_int=>create( seed = cl_abap_random=>seed( )
min = 1
max = len )->get_next( ).
ENDIF.
ENDIF.
DO len TIMES.
DATA(num) = cl_abap_random_int=>create( seed = cl_abap_random=>seed( )
min = 0
max = strlen( number_set ) - 1 )->get_next( ).
numbers &&= number_set+num(1).
ENDDO.
ENDMETHOD.
METHOD get_random_i.
RETURN cl_abap_random_int=>create( seed = cl_abap_random=>seed( )
min = min_value
max = max_value )->get_next( ).
ENDMETHOD.
METHOD get_random_int8.
RETURN cl_abap_random_int8=>create( seed = cl_abap_random=>seed( )
min = min_value
max = max_value )->get_next( ).
ENDMETHOD.
METHOD get_random_p.
IF length NOT BETWEEN 1 AND 16.
RETURN.
ENDIF.
IF decimals NOT BETWEEN 0 AND 14.
RETURN.
ENDIF.
TRY.
CASE decimals.
WHEN 0.
DATA(a) = cl_abap_random_packed=>create( seed = cl_abap_random=>seed( ) min = CONV cl_abap_random_packed=>p31_0( min_value ) max = CONV cl_abap_random_packed=>p31_0( max_value ) )->get_next( ).
CREATE DATA packed_number LIKE a.
packed_number->* = a.
WHEN 1.
DATA(b) = cl_abap_random_packed_dec1=>create( seed = cl_abap_random=>seed( )
min = COND #( WHEN length = 1 THEN CONV cl_abap_random_packed_dec1=>p31_1( '0.1' ) ELSE CONV cl_abap_random_packed_dec1=>p31_1( min_value ) )
max = COND #( WHEN length = 1 THEN CONV cl_abap_random_packed_dec1=>p31_1( '0.9' ) ELSE CONV cl_abap_random_packed_dec1=>p31_1( max_value ) )
)->get_next( ).
CREATE DATA packed_number LIKE b.
packed_number->* = b.
WHEN 2.
DATA(c) = cl_abap_random_packed_dec2=>create( seed = cl_abap_random=>seed( ) min = CONV cl_abap_random_packed_dec2=>p31_2( min_value ) max = CONV cl_abap_random_packed_dec2=>p31_2( max_value ) )->get_next( ).
CREATE DATA packed_number LIKE c.
packed_number->* = c.
WHEN 3.
DATA(d) = cl_abap_random_packed_dec3=>create( seed = cl_abap_random=>seed( ) min = CONV cl_abap_random_packed_dec3=>p31_3( min_value ) max = CONV cl_abap_random_packed_dec3=>p31_3( max_value ) )->get_next( ).
CREATE DATA packed_number LIKE d.
packed_number->* = d.
WHEN 4.
DATA(e) = cl_abap_random_packed_dec4=>create( seed = cl_abap_random=>seed( ) min = CONV cl_abap_random_packed_dec4=>p31_4( min_value ) max = CONV cl_abap_random_packed_dec4=>p31_4( max_value ) )->get_next( ).
CREATE DATA packed_number LIKE e.
packed_number->* = e.
WHEN 5.
DATA(f) = cl_abap_random_packed_dec5=>create( seed = cl_abap_random=>seed( ) min = CONV cl_abap_random_packed_dec5=>p31_5( min_value ) max = CONV cl_abap_random_packed_dec5=>p31_5( max_value ) )->get_next( ).
CREATE DATA packed_number LIKE f.
packed_number->* = f.
WHEN 6.
DATA(g) = cl_abap_random_packed_dec6=>create( seed = cl_abap_random=>seed( ) min = CONV cl_abap_random_packed_dec6=>p31_6( min_value ) max = CONV cl_abap_random_packed_dec6=>p31_6( max_value ) )->get_next( ).
CREATE DATA packed_number LIKE g.
packed_number->* = g.
WHEN 7.
DATA(h) = cl_abap_random_packed_dec7=>create( seed = cl_abap_random=>seed( ) min = CONV cl_abap_random_packed_dec7=>p31_7( min_value ) max = CONV cl_abap_random_packed_dec7=>p31_7( max_value ) )->get_next( ).
CREATE DATA packed_number LIKE h.
packed_number->* = h.
WHEN 8.
DATA(i) = cl_abap_random_packed_dec8=>create( seed = cl_abap_random=>seed( ) min = CONV cl_abap_random_packed_dec8=>p31_8( min_value ) max = CONV cl_abap_random_packed_dec8=>p31_8( max_value ) )->get_next( ).
CREATE DATA packed_number LIKE i.
packed_number->* = i.
WHEN 9.
DATA(j) = cl_abap_random_packed_dec9=>create( seed = cl_abap_random=>seed( ) min = CONV cl_abap_random_packed_dec9=>p31_9( min_value ) max = CONV cl_abap_random_packed_dec9=>p31_9( max_value ) )->get_next( ).
CREATE DATA packed_number LIKE j.
packed_number->* = j.
WHEN 10.
DATA(k) = cl_abap_random_packed_dec10=>create( seed = cl_abap_random=>seed( ) min = CONV cl_abap_random_packed_dec10=>p31_10( min_value ) max = CONV cl_abap_random_packed_dec10=>p31_10( max_value ) )->get_next( ).
CREATE DATA packed_number LIKE k.
packed_number->* = k.
WHEN 11.
DATA(l) = cl_abap_random_packed_dec11=>create( seed = cl_abap_random=>seed( ) min = CONV cl_abap_random_packed_dec11=>p31_11( min_value ) max = CONV cl_abap_random_packed_dec11=>p31_11( max_value ) )->get_next( ).
CREATE DATA packed_number LIKE l.
packed_number->* = l.
WHEN 12.
DATA(m) = cl_abap_random_packed_dec12=>create( seed = cl_abap_random=>seed( ) min = CONV cl_abap_random_packed_dec12=>p31_12( min_value ) max = CONV cl_abap_random_packed_dec12=>p31_12( max_value ) )->get_next( ).
CREATE DATA packed_number LIKE m.
packed_number->* = m.
WHEN 13.
DATA(n) = cl_abap_random_packed_dec13=>create( seed = cl_abap_random=>seed( ) min = CONV cl_abap_random_packed_dec13=>p31_13( min_value ) max = CONV cl_abap_random_packed_dec13=>p31_13( max_value ) )->get_next( ).
CREATE DATA packed_number LIKE n.
packed_number->* = n.
WHEN 14.
DATA(o) = cl_abap_random_packed_dec14=>create( seed = cl_abap_random=>seed( ) min = CONV cl_abap_random_packed_dec14=>p31_14( min_value ) max = CONV cl_abap_random_packed_dec14=>p31_14( max_value ) )->get_next( ).
CREATE DATA packed_number LIKE o.
packed_number->* = o.
ENDCASE.
CATCH cx_root.
ENDTRY.
ENDMETHOD.
METHOD get_random_n.
IF length > max_length OR length < 1.
DATA(len) = max_length.
ELSE.
len = length.
ENDIF.
random_n = get_random_number_sequence( len ).
ENDMETHOD.
METHOD get_random_d.
DATA(int) = cl_abap_random_int=>create( seed = cl_abap_random=>seed( )
min = -100
max = 100 )->get_next( ).
random_d = start_date + int.
ENDMETHOD.
METHOD get_random_t.
DATA(int) = cl_abap_random_int=>create( seed = cl_abap_random=>seed( )
min = -36000
max = 36000 )->get_next( ).
random_t = start_time + int.
ENDMETHOD.
METHOD get_random_utclong.
DATA(int) = cl_abap_random_int=>create( seed = cl_abap_random=>seed( )
min = -100
max = 100 )->get_next( ).
random_utc = utclong_add( val = utclong_current( )
days = int
hours = int
minutes = int
seconds = int ).
ENDMETHOD.
METHOD get_random_dec16.
random_dec16 = cl_abap_random_decfloat16=>create( seed = cl_abap_random=>seed( ) )->get_next( ).
ENDMETHOD.
METHOD get_random_dec34.
random_dec34 = cl_abap_random_decfloat34=>create( seed = cl_abap_random=>seed( ) )->get_next( ).
ENDMETHOD.
METHOD get_random_f.
random_f = cl_abap_random_float=>create( seed = cl_abap_random=>seed( ) )->get_next( ).
ENDMETHOD.
METHOD get_random_x.
DATA(random_string) = get_random_string( length ).
random_x = cl_abap_conv_codepage=>create_out( codepage = `UTF-8` )->convert( random_string ).
ENDMETHOD.
METHOD get_random_xstring.
DATA(random_string) = get_random_string( ).
random_xstring = cl_abap_conv_codepage=>create_out( codepage = `UTF-8` )->convert( random_string ).
ENDMETHOD.
METHOD add_table_entries.
IF table_entry_count < 0.
table_entry_count = 1.
ENDIF.
IF table_entry_count > max_table_entry_count.
table_entry_count = max_table_entry_count.
ENDIF.
DO table_entry_count TIMES.
INSERT INITIAL LINE INTO TABLE itab->* ASSIGNING FIELD-SYMBOL( |
| Class include | Code |
| Global class | ``` abap CLASS zcl_demo_abap DEFINITION PUBLIC FINAL CREATE PUBLIC . PUBLIC SECTION. INTERFACES if_oo_adt_classrun. PROTECTED SECTION. PRIVATE SECTION. ENDCLASS. CLASS zcl_demo_abap IMPLEMENTATION. METHOD if_oo_adt_classrun~main. DATA(divider) = |{ repeat( val = `_` occ = 75 ) }\n|. "---------------- Basic pizza ---------------- DATA(basic_pizza) = NEW lcl_basic_pizza( 10 ). DATA(basic_pizza_created) = basic_pizza->lif_pizza~create_pizza( ). DATA(basic_pizza_costs) = basic_pizza->lif_pizza~get_costs( ). out->write( `Basic pizza` ). out->write( |\nIngredients:| ). out->write( basic_pizza_created ). out->write( |\nCosts:| ). out->write( basic_pizza_costs ). out->write( divider ). "---------------- Salami pizza ---------------- DATA(salami_pizza) = NEW lcl_decorator_salami( pizza = basic_pizza ). DATA(salami_pizza_created) = salami_pizza->lif_pizza~create_pizza( ). DATA(salami_pizza_costs) = salami_pizza->lif_pizza~get_costs( ). out->write( `Salami pizza` ). out->write( |\nIngredients:| ). out->write( salami_pizza_created ). out->write( |\nCosts:| ). out->write( salami_pizza_costs ). out->write( divider ). "---------------- Vegetable pizza ---------------- DATA(vegetarian_pizza) = NEW lcl_decorator_vegetables( pizza = basic_pizza ). DATA(vegetarian_pizza_created) = vegetarian_pizza->lif_pizza~create_pizza( ). DATA(vegetarian_pizza_costs) = vegetarian_pizza->lif_pizza~get_costs( ). out->write( `Vegetable pizza` ). out->write( |\nIngredients:| ). out->write( vegetarian_pizza_created ). out->write( |\nCosts:| ). out->write( vegetarian_pizza_costs ). out->write( divider ). "---------------- Vegetable/salami pizza ---------------- DATA(vegetable_salami_pizza) = NEW lcl_decorator_vegetables( pizza = NEW lcl_decorator_salami( pizza = NEW lcl_basic_pizza( 10 ) ) ). DATA(vegetable_salami_pizza_created) = vegetable_salami_pizza->lif_pizza~create_pizza( ). DATA(vegetable_salami_pizza_costs) = vegetable_salami_pizza->lif_pizza~get_costs( ). out->write( `Vegetable/salami pizza` ). out->write( |\nIngredients:| ). out->write( vegetable_salami_pizza_created ). out->write( |\nCosts:| ). out->write( vegetable_salami_pizza_costs ). out->write( divider ). "---------------- Mushroom/salami pizza ---------------- DATA(mushrooms_salami_pizza) = NEW lcl_decorator_mushrooms( pizza = NEW lcl_decorator_salami( pizza = NEW lcl_basic_pizza( 10 ) ) ). DATA(mushrooms_salami_pizza_created) = mushrooms_salami_pizza->lif_pizza~create_pizza( ). DATA(mushrooms_salami_pizza_costs) = mushrooms_salami_pizza->lif_pizza~get_costs( ). out->write( `Mushrooms/salami pizza` ). out->write( |\nIngredients:| ). out->write( mushrooms_salami_pizza_created ). out->write( |\nCosts:| ). out->write( mushrooms_salami_pizza_costs ). out->write( divider ). "--- Various pizzas (created using the same interface reference variable) --- DATA some_pizza TYPE REF TO lif_pizza. some_pizza = NEW lcl_basic_pizza( 10 ). DATA(some_pizza_created_a) = some_pizza->create_pizza( ). DATA(some_pizza_costs_a) = some_pizza->get_costs( ). some_pizza = NEW lcl_decorator_vegetables( pizza = some_pizza ). DATA(some_pizza_created_b) = some_pizza->create_pizza( ). DATA(some_pizza_costs_b) = some_pizza->get_costs( ). some_pizza = NEW lcl_decorator_salami( pizza = some_pizza ). DATA(some_pizza_created_c) = some_pizza->create_pizza( ). DATA(some_pizza_costs_c) = some_pizza->get_costs( ). "---------------- Allergy-friendly vegetable pizza ---------------- DATA(allergy_friendly_vegetbl_pizza) = NEW lcl_decorator_allergy_friendly( pizza = NEW lcl_decorator_vegetables( pizza = NEW lcl_basic_pizza( 10 ) ) ). DATA(all_friendly_veg_pizza_created) = allergy_friendly_vegetbl_pizza->lif_pizza~create_pizza( ). DATA(all_friendly_veg_pizza_costs) = allergy_friendly_vegetbl_pizza->lif_pizza~get_costs( ). out->write( `Allergy-friendly vegetable pizza` ). out->write( |\nIngredients:| ). out->write( all_friendly_veg_pizza_created ). out->write( |\nCosts:| ). out->write( all_friendly_veg_pizza_costs ). out->write( divider ). "---------------- Pizza with all ingredients ---------------- "Using all concrete decorator classes of the example DATA(misc_pizza) = NEW lcl_decorator_allergy_friendly( pizza = NEW lcl_decorator_mushrooms( pizza = NEW lcl_decorator_salami( pizza = NEW lcl_decorator_vegetables( pizza = NEW lcl_basic_pizza( 10 ) ) ) ) ). DATA(misc_pizza_created) = misc_pizza->lif_pizza~create_pizza( ). DATA(misc_pizza_costs) = misc_pizza->lif_pizza~get_costs( ). out->write( `Pizza with all ingredients` ). out->write( |\nIngredients:| ). out->write( misc_pizza_created ). out->write( |\nCosts:| ). out->write( misc_pizza_costs ). ENDMETHOD. ENDCLASS. ``` |
| CCIMP include (Local Types tab in ADT) | ``` abap ********************************************************************** "Interface INTERFACE lif_pizza. METHODS create_pizza RETURNING VALUE(ingredients) TYPE string_table. METHODS get_costs RETURNING VALUE(costs) TYPE i. ENDINTERFACE. ********************************************************************** "Basic pizza to be decorated CLASS lcl_basic_pizza DEFINITION. PUBLIC SECTION. INTERFACES lif_pizza. METHODS constructor IMPORTING basic_pizza_costs TYPE i. PRIVATE SECTION. DATA pizza_costs TYPE i. ENDCLASS. CLASS lcl_basic_pizza IMPLEMENTATION. METHOD constructor. pizza_costs = basic_pizza_costs. ENDMETHOD. METHOD lif_pizza~create_pizza. ingredients = VALUE #( ( `dough` ) ( `tomato sauce` ) ( `cheese` ) ). ENDMETHOD. METHOD lif_pizza~get_costs. costs = pizza_costs. ENDMETHOD. ENDCLASS. ********************************************************************** "Abstract decorator class CLASS lcl_pizza_decorator DEFINITION ABSTRACT. PUBLIC SECTION. INTERFACES lif_pizza. METHODS constructor IMPORTING pizza TYPE REF TO lif_pizza. PROTECTED SECTION. DATA decorated_pizza TYPE REF TO lif_pizza. ENDCLASS. CLASS lcl_pizza_decorator IMPLEMENTATION. METHOD constructor. decorated_pizza = pizza. ENDMETHOD. METHOD lif_pizza~create_pizza. ingredients = decorated_pizza->create_pizza( ). ENDMETHOD. METHOD lif_pizza~get_costs. costs = decorated_pizza->get_costs( ). ENDMETHOD. ENDCLASS. ********************************************************************** "Concrete decorator classes CLASS lcl_decorator_salami DEFINITION INHERITING FROM lcl_pizza_decorator. PUBLIC SECTION. METHODS constructor IMPORTING pizza TYPE REF TO lif_pizza. METHODS lif_pizza~create_pizza REDEFINITION. METHODS lif_pizza~get_costs REDEFINITION. ENDCLASS. CLASS lcl_decorator_salami IMPLEMENTATION. METHOD constructor. super->constructor( pizza ). ENDMETHOD. METHOD lif_pizza~create_pizza. ingredients = super->lif_pizza~create_pizza( ). APPEND `salami` TO ingredients. ENDMETHOD. METHOD lif_pizza~get_costs. costs = super->lif_pizza~get_costs( ) + 1. ENDMETHOD. ENDCLASS. CLASS lcl_decorator_mushrooms DEFINITION INHERITING FROM lcl_pizza_decorator. PUBLIC SECTION. METHODS constructor IMPORTING pizza TYPE REF TO lif_pizza. METHODS lif_pizza~create_pizza REDEFINITION. METHODS lif_pizza~get_costs REDEFINITION. ENDCLASS. CLASS lcl_decorator_mushrooms IMPLEMENTATION. METHOD constructor. super->constructor( pizza ). ENDMETHOD. METHOD lif_pizza~create_pizza. ingredients = super->lif_pizza~create_pizza( ). APPEND `mushrooms` TO ingredients. ENDMETHOD. METHOD lif_pizza~get_costs. costs = super->lif_pizza~get_costs( ) + 1. ENDMETHOD. ENDCLASS. CLASS lcl_decorator_vegetables DEFINITION INHERITING FROM lcl_pizza_decorator. PUBLIC SECTION. METHODS constructor IMPORTING pizza TYPE REF TO lif_pizza. METHODS lif_pizza~create_pizza REDEFINITION. METHODS lif_pizza~get_costs REDEFINITION. ENDCLASS. CLASS lcl_decorator_vegetables IMPLEMENTATION. METHOD constructor. super->constructor( pizza ). ENDMETHOD. METHOD lif_pizza~create_pizza. ingredients = super->lif_pizza~create_pizza( ). APPEND LINES OF VALUE string_table( ( `red pepper` ) ( `zucchini` ) ( `broccoli` ) ) TO ingredients. ENDMETHOD. METHOD lif_pizza~get_costs. costs = super->lif_pizza~get_costs( ) + 2. ENDMETHOD. ENDCLASS. CLASS lcl_decorator_allergy_friendly DEFINITION INHERITING FROM lcl_pizza_decorator. PUBLIC SECTION. METHODS constructor IMPORTING pizza TYPE REF TO lif_pizza. METHODS lif_pizza~create_pizza REDEFINITION. METHODS lif_pizza~get_costs REDEFINITION. ENDCLASS. CLASS lcl_decorator_allergy_friendly IMPLEMENTATION. METHOD constructor. super->constructor( pizza ). ENDMETHOD. METHOD lif_pizza~create_pizza. ingredients = super->lif_pizza~create_pizza( ). REPLACE ALL OCCURRENCES OF `dough` IN TABLE ingredients WITH `gluten-free dough`. REPLACE ALL OCCURRENCES OF `cheese` IN TABLE ingredients WITH `lactose-free cheese`. ENDMETHOD. METHOD lif_pizza~get_costs. costs = super->lif_pizza~get_costs( ) + 1. ENDMETHOD. ENDCLASS. ``` |
Demo ABAP Doc comments
"! "!This class serves as an example to illustrate comments for ABAP Doc.
"! The comments begin with the string "!, a special form of regular comments introduced by ".
"! The {@link zcl_demo_abap.METH:calculate} method of the example class performs a calculation.
This method performs a calculation.
"! @parameter num1 | First number for the calcation "! @parameter num2 | Second number for the calcation "! @parameter operator | Operator. Only one of the four operators +, -, *, / is allowed. "! The value is represented by an enumerated type. Note that there is no handling if "! the assigned value is initial. "! @parameter result | Result of the calculation "! @raising cx_sy_zerodivide | Zero division "! @raising cx_sy_arithmetic_overflow | Arithmetic overflow CLASS-METHODS calculate IMPORTING num1 TYPE i num2 TYPE i operator TYPE t_enum_calc RETURNING VALUE(result) TYPE decfloat34 RAISING cx_sy_zerodivide cx_sy_arithmetic_overflow. "! This is an ABAP Doc comment for a constant CONSTANTS const TYPE i VALUE 123. "! This is an ABAP Doc comment for a static attribute of a class CLASS-DATA dobj TYPE i. PROTECTED SECTION. PRIVATE SECTION. ENDCLASS. CLASS zcl_demo_abap IMPLEMENTATION. METHOD if_oo_adt_classrun~main. DATA(result_plus) = calculate( num1 = 1 num2 = 10 operator = en_calc-plus ). DATA(result_minus) = calculate( num1 = 1 num2 = 10 operator = en_calc-minus ). DATA(result_multiply) = calculate( num1 = 2 num2 = 5 operator = en_calc-multiply ). DATA(result_divide) = calculate( num1 = 10 num2 = 5 operator = en_calc-divide ). out->write( data = result_plus name = `result_plus` ). out->write( data = result_minus name = `result_minus` ). out->write( data = result_multiply name = `result_multiply` ). out->write( data = result_divide name = `result_divide` ). ENDMETHOD. METHOD calculate. result = SWITCH #( operator WHEN en_calc-plus THEN num1 + num2 WHEN en_calc-minus THEN num1 - num2 WHEN en_calc-multiply THEN num1 * num2 WHEN en_calc-divide THEN num1 / num2 ELSE '0' ). ENDMETHOD. ENDCLASS. ``` ### Escape Character - You may encounter [`!` characters](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/ABENNAMES_ESCAPING.html) specified before operands, particularly in signatures of [procedures](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenprocedure_glosry.htm). - They are used to distinguish the operand's name from ABAP words. - When compiling ABAP programs, the specifications with the escape character are not considered as ABAP words. - When executing the programs, the escape characters are ignored. The following nonsensical example shows various specifications with the escape character that emphasize in the program that the operands are not to be confused with ABAP words. These specifications are not mandatory in the example. The example only addresses escape characters you may encounter in ABAP code. ```abap CLASS zcl_demo_abap DEFINITION PUBLIC FINAL CREATE PUBLIC . PUBLIC SECTION. INTERFACES if_oo_adt_classrun. DATA num TYPE i. CLASS-DATA default TYPE i VALUE 1. METHODS meth1 IMPORTING !num TYPE i. METHODS !methods IMPORTING !raising TYPE i OPTIONAL !optional TYPE i !exporting TYPE i EXPORTING !importing TYPE i !changing TYPE i CHANGING !default TYPE i. PROTECTED SECTION. PRIVATE SECTION. ENDCLASS. CLASS zcl_demo_abap IMPLEMENTATION. METHOD if_oo_adt_classrun~main. meth1( 1 ). DATA !exporting TYPE i. DATA !changing TYPE i. methods( EXPORTING raising = 1 optional = 5 exporting = 10 IMPORTING importing = !exporting changing = !changing CHANGING default = !default ). ENDMETHOD. METHOD meth1. DATA(a) = num. DATA(b) = me->num. DATA(c) = !num. me->num = num. me->num = !num. ENDMETHOD. METHOD methods. !importing = !raising + !optional. !changing = !exporting. !default += 1. importing = raising + optional. changing = exporting. default += 1. ENDMETHOD. ENDCLASS. ``` ## More Information You can check the subtopics of - [ABAP Objects - Overview](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenabap_objects_oview.htm) - [Programming Guidlines - Object-Oriented Programming (F1 docu for standard ABAP)](https://help.sap.com/doc/abapdocu_latest_index_htm/latest/en-US/index.htm?file=abenobj_oriented_gdl.htm) in the ABAP Keyword Documentation. ## Executable Examples - [zcl_demo_abap_objects](./src/zcl_demo_abap_objects.clas.abap) - [zcl_demo_abap_objects_misc](./src/zcl_demo_abap_objects_misc.clas.abap): Additional syntax examples - [zcl_demo_abap_oo_inheritance_1](./src/zcl_demo_abap_oo_inheritance_1.clas.abap): Focuses on inheritance; the inheritance tree consists of 4 example classes > **💡 Note**