Iterator
Iterator — поведінковий патерн, що дає універсальний спосіб обходити колекцію, не розкриваючи, як саме вона зберігає дані. Клієнт отримує обʼєкт-ітератор з методами has_next( ) / next( ) і не замислюється, чи це standard table, hashed table, дерево чи курсор на БД.
Метафора
Section titled “Метафора”Пульт телевізора з кнопкою «наступний канал». Тобі неважливо, як телевізор всередині зберігає список каналів, відсортований він чи ні, з кабелю чи ефіру — ти просто натискаєш «next», і отримуєш наступний.
Коли застосовувати
Section titled “Коли застосовувати”- Колекція має нетривіальну структуру (дерево, граф, курсор на БД, потік файлу) — прямий
LOOP ATнеможливий або незручний. - Потрібно кілька активних обходів одної колекції одночасно (два ітератори не заважають один одному).
- Хочеш приховати внутрішнє представлення — клієнт працює тільки через ітератор.
- Послідовність обходу залежить від стратегії (сортування, фільтр) — ітератор інкапсулює стратегію.
ABAP-реалізація
Section titled “ABAP-реалізація”INTERFACE zif_iterator. METHODS: has_next RETURNING VALUE(rv) TYPE abap_bool, next RETURNING VALUE(rr) TYPE REF TO data RAISING zcx_iterator_exhausted.ENDINTERFACE.
" Колекція, що вміє видавати ітераторINTERFACE zif_iterable. METHODS create_iterator RETURNING VALUE(ro) TYPE REF TO zif_iterator.ENDINTERFACE.
" Конкретна колекція — деревоCLASS zcl_tree DEFINITION PUBLIC FINAL CREATE PUBLIC. PUBLIC SECTION. INTERFACES zif_iterable. METHODS: add_node IMPORTING iv_value TYPE string. PRIVATE SECTION. DATA mt_nodes TYPE STANDARD TABLE OF zty_node WITH EMPTY KEY.ENDCLASS.
" Ітератор — окремий клас, що тримає позиціюCLASS zcl_tree_iterator DEFINITION PUBLIC FINAL CREATE PRIVATE FRIENDS zcl_tree.
PUBLIC SECTION. INTERFACES zif_iterator.
PRIVATE SECTION. METHODS constructor IMPORTING io_tree TYPE REF TO zcl_tree. DATA: mo_tree TYPE REF TO zcl_tree, mv_pos TYPE i.ENDCLASS.Використання — як у GoF:
DATA(lo_it) = lo_tree->zif_iterable~create_iterator( ).WHILE lo_it->has_next( ) = abap_true. DATA(lr_value) = lo_it->next( ). " ...ENDWHILE.Коли вистачить LOOP AT
Section titled “Коли вистачить LOOP AT”У 95% випадків ABAP не потребує явного Iterator-патерну — LOOP AT itab і так універсальний. Іди у Iterator лише коли:
- внутрішня структура — НЕ таблиця (дерево, граф, курсор);
- структура НЕ має бути видимою клієнту (інкапсуляція);
- ітерація має власний стан (позиція), що переживає між викликами методів.
SAP-специфіка
Section titled “SAP-специфіка”- iXML API (
if_ixml_node_iterator,if_ixml_node_collection) — канонічний Iterator у SAP-стандарті: обхід DOM-дерева без оголення структури. cl_abap_typedescr,cl_abap_structdescr— отримання компонентів черезget_components( )повертає таблицю; для DDIC-дерев iterator-подібний API.- Cursor-based SELECT (
OPEN CURSOR,FETCH NEXT CURSOR) — по суті Iterator над БД-результатом. - Streams (
CL_ABAP_GZIP, файлові потоки) — ітератор над байтами.
Підводні камені
Section titled “Підводні камені”- Одночасна модифікація колекції під час ітерації. Якщо клієнт додає елемент у колекцію під час обходу — ітератор може впасти або дати невалідні дані. Або блокуй модифікації на час ітерації, або явно документуй поведінку (fail-fast vs fail-safe).
- Повторний обхід. Деякі ітератори — одноразові (курсор на БД закрився після
FETCH). Клієнт думає, що може запуститиhas_nextзнову з початку, а отримує порожньо. Документуй контракт. RETURNING VALUE(rr) TYPE REF TO data— ABAP не дає generics, тож ітератор над типізованою таблицею або віддає загальнийREF TO data(требаASSIGN), або — один клас-ітератор на один тип колекції (громіздко).- Витоки. Якщо клієнт не дійшов до кінця ітерації і кинув ітератор — ресурси (курсор, handle на файл) можуть не звільнитись. Використовуй
TRY ... FINALLY-еквівалент черезCLEANUPабо явнийclose( ).
Коли НЕ використовувати
Section titled “Коли НЕ використовувати”- Дані в
STANDARD TABLE— пишиLOOP ATі не вигадуй. - Потрібно індексоване читання, а не послідовне —
READ TABLE ... INDEX. - Одна проста колекція, один клієнт, видимість структури не турбує — Iterator додасть шуму без вигоди.