Proxy
Proxy — структурний патерн: обʼєкт-заступник реалізує той самий інтерфейс, що і справжній, і клієнт викликає proxy, не знаючи про це. Proxy додає логіку навколо виклику: лінькова ініціалізація, кеш, перевірки, логування звернень, віддалений виклик.
Метафора
Section titled “Метафора”Ресепшн готелю. Гість просить щось — ресепшн вирішує, кликати прибирання, технічну службу чи менеджера. Або сам відповідає («меню в номері, на столі»). Гість не знає, що запит пішов глибше. І коли справжній виконавець зайнятий, ресепшн може обслужити з кешу: «Так, Wi-Fi-пароль той самий, як вчора».
Коли застосовувати
Section titled “Коли застосовувати”- Lazy initialization — важкий обʼєкт створити лише перед першим реальним викликом.
- Кеш — повертати збережений результат, якщо він є.
- Контроль доступу — перевіряти повноваження перед проходом до справжнього обʼєкта.
- Remote proxy — робити RFC/HTTP, приховуючи мережу від клієнта.
- Logging / metrics — трасувати виклики без правки цільового класу.
ABAP-реалізація — Caching Proxy
Section titled “ABAP-реалізація — Caching Proxy”Найчастіший варіант у SAP — кеш. Повний код репозиторію матеріалів із кешем:
INTERFACE zif_material_repo. METHODS get IMPORTING iv_matnr TYPE matnr RETURNING VALUE(rs) TYPE zty_material RAISING zcx_not_found.ENDINTERFACE.
" Реальний репозиторій — дорогий SELECTCLASS zcl_material_repo DEFINITION PUBLIC FINAL CREATE PUBLIC. PUBLIC SECTION. INTERFACES zif_material_repo.ENDCLASS.
CLASS zcl_material_repo IMPLEMENTATION. METHOD zif_material_repo~get. SELECT SINGLE matnr, mtart, meins, brgew FROM mara WHERE matnr = @iv_matnr INTO CORRESPONDING FIELDS OF @rs. IF sy-subrc <> 0. RAISE EXCEPTION NEW zcx_not_found( iv_matnr = iv_matnr ). ENDIF. ENDMETHOD.ENDCLASS.
" Caching proxyCLASS zcl_material_repo_cached DEFINITION PUBLIC FINAL CREATE PUBLIC. PUBLIC SECTION. INTERFACES zif_material_repo. METHODS constructor IMPORTING io_real TYPE REF TO zif_material_repo. PRIVATE SECTION. DATA: mo_real TYPE REF TO zif_material_repo, mt_cache TYPE SORTED TABLE OF zty_material WITH UNIQUE KEY matnr.ENDCLASS.
CLASS zcl_material_repo_cached IMPLEMENTATION. METHOD constructor. mo_real = io_real. ENDMETHOD.
METHOD zif_material_repo~get. READ TABLE mt_cache WITH KEY matnr = iv_matnr ASSIGNING FIELD-SYMBOL(<ls>). IF sy-subrc = 0. rs = <ls>. RETURN. " cache hit ENDIF.
rs = mo_real->get( iv_matnr ). " cache miss → реальний виклик INSERT rs INTO TABLE mt_cache. ENDMETHOD.ENDCLASS.Використання:
DATA(lo_repo) = CAST zif_material_repo( NEW zcl_material_repo_cached( NEW zcl_material_repo( ) ) ).
DATA(ls1) = lo_repo->get( 'MAT001' ). " SELECTDATA(ls2) = lo_repo->get( 'MAT001' ). " з кешуКлієнт не знає про кеш. Щоб «вимкнути» кеш у тестах — підсовуємо напряму zcl_material_repo( ).
Lazy Proxy
Section titled “Lazy Proxy”Важкий обʼєкт не створюється, доки не попросять:
CLASS zcl_heavy_proxy DEFINITION PUBLIC FINAL CREATE PUBLIC. PUBLIC SECTION. INTERFACES zif_heavy. PRIVATE SECTION. DATA mo_real TYPE REF TO zcl_heavy.ENDCLASS.
CLASS zcl_heavy_proxy IMPLEMENTATION. METHOD zif_heavy~do_work. IF mo_real IS NOT BOUND. mo_real = NEW zcl_heavy( ). " створюємо тільки зараз ENDIF. rv = mo_real->do_work( iv_input ). ENDMETHOD.ENDCLASS.Якщо клієнт так і не викличе метод — zcl_heavy взагалі не створиться.
Authorization Proxy
Section titled “Authorization Proxy”Перевірка повноважень перед викликом:
METHOD zif_repo~delete. AUTHORITY-CHECK OBJECT 'Z_REPO' ID 'ACTVT' FIELD '06' ID 'NAME' FIELD iv_id. IF sy-subrc <> 0. RAISE EXCEPTION NEW zcx_not_authorized( iv_activity = 'DELETE' ). ENDIF. mo_real->delete( iv_id ).ENDMETHOD.Proxy vs Decorator
Section titled “Proxy vs Decorator”Структурно однакові. Різниця — у намірі:
- Proxy — керує доступом (lazy, auth, remote, cache). Клієнт часто не здогадується, що це не реальний обʼєкт.
- Decorator — додає поведінку (лог, timestamp, формат). Клієнт свідомо обгортає.
Якщо можеш пояснити свою обгортку як «фільтр доступу» — це Proxy. Якщо як «додавання функціональності» — Decorator.
SAP-специфіка
Section titled “SAP-специфіка”- RFC Proxy classes (
SPROXY, CONSUMER-proxy) — SAP-стандарт genрує proxy для віддалених викликів. cl_abap_proxy_framework— infrastructural proxy для web-servic-і.- Authorization proxies довкола BAPI: типове рішення — загортати BAPI у authority-проксі на рівні wrapper-класів.
- Caching proxy над DAO/model-класом — природне місце, коли метод читає одне й те саме з важкого
SELECTкілька разів за сесію.
Підводні камені
Section titled “Підводні камені”- Валідація кешу. Кеш без інвалідації — баг-генератор. Визначи стратегію: TTL? invalidate on write?
CLEAR mt_cacheна певну подію? - Cache coherence. Якщо два обʼєкти мають свій кеш — зміна в одному не відбивається в іншому. Для критичних даних — один загальний кеш (singleton-кеш зі scope-ом на session).
- Propagation of errors. Proxy має перекидати винятки прозоро, не обгортати у свої, якщо немає додаткового контексту.
- Якщо proxy тоненький — не городь. Просто виклик, що перевіряє
IS BOUND— не потребує окремого класу. Proxy виправданий, коли має свою стабільну інваріантну логіку.
Коли НЕ використовувати
Section titled “Коли НЕ використовувати”- Дія тривіальна і одноразова —
IF mo_obj IS INITIAL. mo_obj = NEW ...( ). ENDIF.не потребує класу. - Клієнт хоче бачити і керувати — наприклад, хоче явний
cache.clear( ). Тоді потрібен Decorator з додатковими методами, не Proxy. - Інтерфейс часто змінюється — proxy доведеться оновлювати щоразу.