Mediator
Mediator — поведінковий патерн: замість того, щоб обʼєкти знали один про одного і викликали один одного напряму, вони спілкуються через центрального посередника. Посередник інкапсулює правила взаємодії, компоненти стають незалежними, систему простіше міняти.
Метафора
Section titled “Метафора”Диспетчерська вежа аеропорту. Пілоти не домовляються з пілотами інших літаків напряму — вони говорять з диспетчером. Диспетчер знає всіх і координує, хто коли злітає, сідає, куди рулює. Забери диспетчера — літаки не знатимуть, як взаємодіяти.
Коли застосовувати
Section titled “Коли застосовувати”- Система має багато компонентів, що тісно переплетені — кожен знає про кількох сусідів, зміна одного тягне правки всіх.
- Треба централізувати складні правила взаємодії між UI-елементами (зміна одного поля вмикає/вимикає інші).
- Хочеш тестувати компоненти ізольовано — напряму вони не знають один одного, тільки про mediator-інтерфейс.
- Додавання нового компонента не повинно тягти правки існуючих.
ABAP-реалізація
Section titled “ABAP-реалізація”" Контракт посередникаINTERFACE zif_mediator. METHODS notify IMPORTING io_sender TYPE REF TO object iv_event TYPE string is_data TYPE any OPTIONAL.ENDINTERFACE.
" Базовий клас компонента — тримає ref на mediatorCLASS zcl_form_component DEFINITION PUBLIC ABSTRACT. PUBLIC SECTION. METHODS constructor IMPORTING io_mediator TYPE REF TO zif_mediator. PROTECTED SECTION. DATA mo_mediator TYPE REF TO zif_mediator.ENDCLASS.
CLASS zcl_form_component IMPLEMENTATION. METHOD constructor. mo_mediator = io_mediator. ENDMETHOD.ENDCLASS.
" Конкретний компонент — поле вибору країниCLASS zcl_field_country DEFINITION PUBLIC FINAL INHERITING FROM zcl_form_component. PUBLIC SECTION. METHODS set_value IMPORTING iv_country TYPE land1.ENDCLASS.
CLASS zcl_field_country IMPLEMENTATION. METHOD set_value. mo_mediator->notify( io_sender = me iv_event = 'COUNTRY_CHANGED' is_data = iv_country ). ENDMETHOD.ENDCLASS.
" Конкретний посередник — правила координаціїCLASS zcl_form_mediator DEFINITION PUBLIC FINAL CREATE PUBLIC. PUBLIC SECTION. INTERFACES zif_mediator.
METHODS: register_country IMPORTING io TYPE REF TO zcl_field_country, register_region IMPORTING io TYPE REF TO zcl_field_region, register_city IMPORTING io TYPE REF TO zcl_field_city.
PRIVATE SECTION. DATA: mo_country TYPE REF TO zcl_field_country, mo_region TYPE REF TO zcl_field_region, mo_city TYPE REF TO zcl_field_city.ENDCLASS.
CLASS zcl_form_mediator IMPLEMENTATION. METHOD zif_mediator~notify. CASE iv_event. WHEN 'COUNTRY_CHANGED'. mo_region->reset_list( is_data ). mo_city->reset_list( ). WHEN 'REGION_CHANGED'. mo_city->reset_list( is_data ). ENDCASE. ENDMETHOD.ENDCLASS.Результат: поле «країна» не знає про поля «регіон» і «місто». Воно просто каже посереднику «країна змінилась» — правило «при зміні країни почистити регіон і місто» знаходиться в одному місці.
Mediator vs Observer
Section titled “Mediator vs Observer”Схоже, але не те саме:
| Mediator | Observer | |
|---|---|---|
| Канали | Багато-до-багатьох через центр | Один-до-багатьох, subject → observers |
| Семантика | Координація (правила взаємодії) | Сповіщення (подія → реакція) |
| Знання | Mediator знає всіх | Subject не знає, хто підписаний |
| Звʼязки | Компоненти знають mediator | Observer знає subject, не навпаки |
Можна комбінувати: mediator всередині використовує events для підписки, але для клієнтів — один вхід у notify( ).
SAP-специфіка
Section titled “SAP-специфіка”cl_gui_cfw(Control Framework) — фактично mediator між ABAP-кодом та GUI-контролами.cl_gui_cfw=>dispatch( ),flush( ).- Business Communication Services (BCS) — mediator між вхідними email/fax/SMS і обробниками.
- Controller у MVC — класичне місце для mediator: координує model і view, щоб вони не знали один про одного напряму.
Підводні камені
Section titled “Підводні камені”- Компоненти залежать від mediator. Гірше — усі залежать від одного типу mediator. Використовуй інтерфейс
zif_mediatorі передавай через конструктор (DI). - Цикли. Якщо mediator у відповідь на подію просить компонент щось зробити, а той знову повідомляє mediator — нескінченна рекурсія. Додавай прапорець «зараз у відповідь на подію X — не реагуй».
- Тяжко дебажити. Потік керування непрямий: «хто кого викликав?» — треба читати mediator. Логуй виклики
notifyз sender-ом і event-ом.
Коли НЕ використовувати
Section titled “Коли НЕ використовувати”- Компонентів 2-3 — вони можуть знати один одного напряму.
- Взаємодія проста — один метод у одному класі.
- Немає ризику, що компонентів стане більше — не ускладнюй заздалегідь.