Класи та об'єкти
ABAP Objects — обʼєктно-орієнтована частина мови: класи, інтерфейси, спадкування, поліморфізм. У сучасному ABAP (особливо в ABAP Cloud) бізнес-логіка пишеться у класах — процедурні програми і function modules залишаються для legacy та тонких шарів інтеграції.
Клас — шаблон. На ньому будується екземпляр (instance) з власним станом. Клас складається з двох частин: DEFINITION (оголошення компонентів) і IMPLEMENTATION (тіла методів).
Локальний vs глобальний клас
Section titled “Локальний vs глобальний клас”| Тип | Де живе | Область видимості |
|---|---|---|
| Local class | всередині ABAP-програми (CCIMP, report) | тільки ця програма |
| Global class | class pool як repository object | всюди, де видно |
Якщо клас потрібен лише в одній програмі — починай з local. Global робиш тоді, коли його використовуватимуть інші програми. Global маркується додатком PUBLIC у CLASS ... DEFINITION PUBLIC.
Скелет класу
Section titled “Скелет класу”" ОголошенняCLASS zcl_demo DEFINITION PUBLIC " робить клас глобальним FINAL " заборона спадкування CREATE PUBLIC. " екземпляр можна створювати будь-де
PUBLIC SECTION. " публічні компоненти PROTECTED SECTION. " видимі у підкласах PRIVATE SECTION. " видимі тільки всередині цього класуENDCLASS.
" РеалізаціяCLASS zcl_demo IMPLEMENTATION. " тіла методівENDCLASS.Додатки до DEFINITION:
| Додаток | Що робить |
|---|---|
PUBLIC | робить клас глобальним |
FINAL | забороняє успадкування |
ABSTRACT | клас не можна інстанціювати; може містити abstract методи |
CREATE PUBLIC | інстанціювати можна будь-де (за замовчуванням) |
CREATE PROTECTED | тільки у підкласах, самому класі, friends |
CREATE PRIVATE | тільки у самому класі або friends (патерн factory method) |
INHERITING FROM superclass | успадкування від суперкласу |
FOR TESTING | тестовий клас ABAP Unit |
GLOBAL FRIENDS class | надає friend-доступ іншому класу |
Видимість
Section titled “Видимість”Три секції видимості забезпечують інкапсуляцію:
| Доступ із | public | protected | private |
|---|---|---|---|
| Цей клас і його friends | так | так | так |
| Підкласи | так | так | ні |
| Будь-хто ззовні | так | ні | ні |
Атрибути
Section titled “Атрибути”CLASS zcl_demo DEFINITION PUBLIC FINAL CREATE PUBLIC. PUBLIC SECTION. DATA inst_attr TYPE i. " instance-атрибут CLASS-DATA static_attr TYPE string. " static-атрибут (один на клас) CONSTANTS c_pi TYPE p DECIMALS 5 VALUE '3.14159'. TYPES ty_name TYPE c LENGTH 40. PRIVATE SECTION. DATA counter TYPE i.ENDCLASS.CLASS-DATA існує один раз для всього класу — доступ через zcl_demo=>static_attr. DATA існує у кожному екземплярі — через ref->inst_attr.
READ-ONLY дозволяє читати атрибут ззовні, але писати — тільки зсередини класу:
DATA id TYPE i READ-ONLY.Методи
Section titled “Методи”CLASS zcl_demo DEFINITION PUBLIC FINAL CREATE PUBLIC. PUBLIC SECTION. METHODS calc IMPORTING a TYPE i b TYPE i DEFAULT 0 text TYPE string OPTIONAL EXPORTING log TYPE string CHANGING counter TYPE i RETURNING VALUE(result) TYPE i RAISING cx_my_exc.
CLASS-METHODS greet IMPORTING name TYPE string.ENDCLASS.Типи параметрів:
IMPORTING— вхід; за замовчуванням by reference (read-only усередині).EXPORTING— вихід.CHANGING— і вхід, і вихід.RETURNING VALUE(r)— єдине значення; робить метод функціональним (можна використовувати у виразах).RAISING— виняток, який метод може кинути.
VALUE(...) перед іменем — передача за значенням (by value). RETURNING завжди by value.
Виклик
Section titled “Виклик”" Функціональний метод — у виразіDATA(sum) = obj->calc( a = 1 b = 2 ).
" Коли параметр один — можна без іменіDATA(len) = helper->length( `text` ).
" Метод без RETURNINGobj->process( EXPORTING x = 1 IMPORTING y = DATA(y) ).
" Static-методzcl_demo=>greet( `World` ).Конструктори
Section titled “Конструктори”Два види: instance і static.
CLASS zcl_demo DEFINITION PUBLIC CREATE PUBLIC. PUBLIC SECTION. " Instance-конструктор — викликається при NEW METHODS constructor IMPORTING name TYPE string.
" Static-конструктор — викликається один раз при першому доступі до класу CLASS-METHODS class_constructor.ENDCLASS.
CLASS zcl_demo IMPLEMENTATION. METHOD constructor. me->name = name. ENDMETHOD.
METHOD class_constructor. " Ініціалізація CLASS-DATA ENDMETHOD.ENDCLASS.Static-конструктор запускається автоматично при першому зверненні до класу (перший NEW, виклик static-методу, доступ до static-атрибута). Вручну викликати не можна.
Створення обʼєктів
Section titled “Створення обʼєктів”" Оголошення reference-змінноїDATA ref TYPE REF TO zcl_demo.
" Створення інстансаref = NEW #( name = `demo` ).
" Inline — компактноDATA(ref2) = NEW zcl_demo( name = `demo` ).Оператор NEW — сучасний спосіб. Старіший CREATE OBJECT ref EXPORTING ... ще працює, але не треба.
Self-reference me
Section titled “Self-reference me”Усередині instance-методу me — посилання на поточний екземпляр. Потрібне, коли треба розрізнити атрибут і локальну змінну з однаковим іменем:
METHOD constructor. me->name = name. " me->name — атрибут; name — параметрENDMETHOD.Method chaining
Section titled “Method chaining”Якщо метод повертає обʼєкт — виклики можна чейнити:
DATA(result) = factory=>create( )->configure( `x` )->build( ).
" Так само для атрибутівDATA(val) = obj->sub_obj->field.Спадкування
Section titled “Спадкування”CLASS lcl_animal DEFINITION. PUBLIC SECTION. METHODS: constructor IMPORTING name TYPE string, speak RETURNING VALUE(sound) TYPE string. PROTECTED SECTION. DATA name TYPE string.ENDCLASS.
CLASS lcl_dog DEFINITION INHERITING FROM lcl_animal. PUBLIC SECTION. METHODS speak REDEFINITION.ENDCLASS.
CLASS lcl_dog IMPLEMENTATION. METHOD speak. sound = |{ name } гавкає|. ENDMETHOD.ENDCLASS.Правила:
- ABAP підтримує лише одиничне спадкування (один суперклас).
- Усі класи неявно успадковують від
object. REDEFINITIONперевизначає метод суперкласу. Сигнатура зберігається.FINAL METHODS ...— заборона перевизначати конкретний метод.ABSTRACT METHODS ...— метод без тіла, підклас зобовʼязаний реалізувати.
Виклик методу суперкласу
Section titled “Виклик методу суперкласу”METHOD speak. DATA(base_sound) = super->speak( ). sound = |{ base_sound } і гавкає|.ENDMETHOD.Конструктор у підкласі
Section titled “Конструктор у підкласі”CLASS lcl_dog DEFINITION INHERITING FROM lcl_animal. PUBLIC SECTION. METHODS constructor IMPORTING name TYPE string breed TYPE string. PRIVATE SECTION. DATA breed TYPE string.ENDCLASS.
CLASS lcl_dog IMPLEMENTATION. METHOD constructor. super->constructor( name = name ). " обовʼязково першим me->breed = breed. ENDMETHOD.ENDCLASS.Поліморфізм, upcast/downcast
Section titled “Поліморфізм, upcast/downcast”Посилання на суперклас може вказувати на підклас — це основа поліморфізму:
DATA animal TYPE REF TO lcl_animal.animal = NEW lcl_dog( name = `Rex` breed = `husky` ).DATA(sound) = animal->speak( ). " викличеться lcl_dog->speak
" Downcast — отримати посилання конкретного типуDATA dog TYPE REF TO lcl_dog.dog ?= animal. " через оператор ?=DATA(dog2) = CAST lcl_dog( animal ). " те саме через CASTIF animal IS INSTANCE OF lcl_dog. DATA(dog) = CAST lcl_dog( animal ). " ...ENDIF.Абстрактні класи
Section titled “Абстрактні класи”CLASS lcl_shape DEFINITION ABSTRACT. PUBLIC SECTION. METHODS area ABSTRACT RETURNING VALUE(r) TYPE f.ENDCLASS." NEW lcl_shape( ) — помилка компіляціїАбстрактний клас не можна інстанціювати. Абстрактні методи реалізуються у підкласах через REDEFINITION.
Інтерфейси
Section titled “Інтерфейси”Інтерфейс — чистий контракт без реалізації. Клас може реалізовувати кілька інтерфейсів (на відміну від одиничного спадкування):
INTERFACE lif_serializable. METHODS to_json RETURNING VALUE(json) TYPE string.ENDINTERFACE.
INTERFACE lif_named. DATA name TYPE string. METHODS set_name IMPORTING n TYPE string.ENDINTERFACE.
CLASS lcl_user DEFINITION. PUBLIC SECTION. INTERFACES: lif_serializable, lif_named.ENDCLASS.
CLASS lcl_user IMPLEMENTATION. METHOD lif_serializable~to_json. json = |\{"name":"{ lif_named~name }"\}|. ENDMETHOD. METHOD lif_named~set_name. lif_named~name = n. ENDMETHOD.ENDCLASS.Методи інтерфейсу завжди адресуються через ~: lif_serializable~to_json. Це важливо, коли два інтерфейси мають методи з однаковим іменем.
Робота через посилання на інтерфейс
Section titled “Робота через посилання на інтерфейс”DATA srl TYPE REF TO lif_serializable.srl = NEW lcl_user( ).DATA(json) = srl->to_json( ). " без ~, бо srl вже типу інтерфейсаFriendship
Section titled “Friendship”FRIENDS дає іншому класу повний доступ до всіх компонентів, включно з private:
CLASS zcl_secret DEFINITION PUBLIC FINAL CREATE PUBLIC GLOBAL FRIENDS zcl_trusted. PRIVATE SECTION. DATA secret TYPE string.ENDCLASS.
" zcl_trusted тепер може читати/писати secretДля local — CLASS zcl_main DEFINITION LOCAL FRIENDS ltc_test. — класичний патерн для unit-тестів, щоб тест бачив private-методи класу.
Події (events)
Section titled “Події (events)”ABAP має вбудовану підтримку publisher-subscriber через events:
CLASS lcl_button DEFINITION. PUBLIC SECTION. EVENTS click EXPORTING VALUE(x) TYPE i. METHODS press.ENDCLASS.
CLASS lcl_button IMPLEMENTATION. METHOD press. RAISE EVENT click EXPORTING x = 42. ENDMETHOD.ENDCLASS.
CLASS lcl_handler DEFINITION. PUBLIC SECTION. METHODS on_click FOR EVENT click OF lcl_button IMPORTING x.ENDCLASS.
" РеєстраціяDATA(btn) = NEW lcl_button( ).DATA(h) = NEW lcl_handler( ).SET HANDLER h->on_click FOR btn.btn->press( ). " викличе on_clickRETURN
Section titled “RETURN”Достроковий вихід з методу. Якщо є RETURNING VALUE(r) — поверне поточне значення r:
METHOD find. LOOP AT itab INTO DATA(line). IF line-key = key. result = line. RETURN. " вийти з методу одразу ENDIF. ENDLOOP.ENDMETHOD.Шаблон мінімального сервісного класу
Section titled “Шаблон мінімального сервісного класу”CLASS zcl_service DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION. METHODS: constructor IMPORTING dep TYPE REF TO lif_repository, run IMPORTING id TYPE i RETURNING VALUE(result) TYPE string RAISING cx_service_error. PRIVATE SECTION. DATA repo TYPE REF TO lif_repository.ENDCLASS.
CLASS zcl_service IMPLEMENTATION. METHOD constructor. me->repo = dep. ENDMETHOD.
METHOD run. DATA(entity) = repo->get( id ). result = |processed: { entity-name }|. ENDMETHOD.ENDCLASS.Dependency injection через конструктор, посилання на інтерфейс, один публічний метод — типова одиниця сервісу в ABAP Cloud.
Адаптовано з 04_ABAP_Object_Orientation.md (Apache 2.0). Повний перелік нюансів — в оригіналі.