Перейти до вмісту

Bridge

Bridge — структурний патерн: розʼєднати абстракцію (що робимо) і реалізацію (як саме) у дві окремі ієрархії, щоб вони могли змінюватись незалежно. Уникає «декартового добутку» класів, коли треба комбінувати два виміри варіативності.

Пульт і телевізор. Пульт — абстракція (кнопки «гучніше», «канал вгору», «меню»). Телевізор — реалізація (Samsung, LG, Sony). Пульти відрізняються формою/кількістю кнопок; телевізори — протоколами і логікою. Розʼєднаний дизайн дозволяє мати будь-який пульт для будь-якого телевізора, без N × M спеціальних комбінацій.

  • Є два виміри варіативності, що множаться один на одного (наприклад, тип документа × формат виводу: інвойс/замовлення/відвантаження × PDF/XLSX/email).
  • Хочеш уникнути вибуху класів ClassAB, ClassAC, ClassBB, ClassBC
  • Абстракція і реалізація мають різні життєві цикли.
  • Треба підміняти реалізацію у runtime.

Ззовні схожі (обʼєкт тримає посилання на інший обʼєкт):

  • Adapterпостфактум перекладає інтерфейс існуючого класу. Реактивний.
  • Bridgeнаперед спроектований поділ на дві ієрархії. Проактивний.

Приклад: сповіщення (notifications). Два виміри:

  • Тип: звичайне, важливе, urgent
  • Канал: email, SMS, Telegram

Без Bridge — 3 × 3 = 9 класів. З Bridge — 3 + 3 = 6.

" Реалізація (канал доставки) — окрема ієрархія
INTERFACE zif_delivery_channel.
METHODS send
IMPORTING iv_to TYPE string
iv_subject TYPE string
iv_body TYPE string.
ENDINTERFACE.
CLASS zcl_channel_email DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION. INTERFACES zif_delivery_channel.
ENDCLASS.
CLASS zcl_channel_email IMPLEMENTATION.
METHOD zif_delivery_channel~send.
" cl_bcs_message ...
ENDMETHOD.
ENDCLASS.
CLASS zcl_channel_sms DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION. INTERFACES zif_delivery_channel.
ENDCLASS.
CLASS zcl_channel_telegram DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION. INTERFACES zif_delivery_channel.
ENDCLASS.
" Абстракція (тип повідомлення) — своя ієрархія, тримає канал
CLASS zcl_notification DEFINITION PUBLIC ABSTRACT.
PUBLIC SECTION.
METHODS:
constructor IMPORTING io_channel TYPE REF TO zif_delivery_channel,
send IMPORTING iv_to TYPE string
iv_text TYPE string.
PROTECTED SECTION.
DATA mo_channel TYPE REF TO zif_delivery_channel.
ENDCLASS.
CLASS zcl_notification IMPLEMENTATION.
METHOD constructor. mo_channel = io_channel. ENDMETHOD.
METHOD send.
" дефолт — переозначать нащадки
mo_channel->send( iv_to = iv_to iv_subject = 'Info' iv_body = iv_text ).
ENDMETHOD.
ENDCLASS.
" Конкретні «абстракції»
CLASS zcl_notification_normal DEFINITION PUBLIC FINAL INHERITING FROM zcl_notification.
PUBLIC SECTION. METHODS send REDEFINITION.
ENDCLASS.
CLASS zcl_notification_normal IMPLEMENTATION.
METHOD send.
mo_channel->send( iv_to = iv_to iv_subject = 'Інформація' iv_body = iv_text ).
ENDMETHOD.
ENDCLASS.
CLASS zcl_notification_urgent DEFINITION PUBLIC FINAL INHERITING FROM zcl_notification.
PUBLIC SECTION. METHODS send REDEFINITION.
ENDCLASS.
CLASS zcl_notification_urgent IMPLEMENTATION.
METHOD send.
mo_channel->send( iv_to = iv_to
iv_subject = '[URGENT] Терміново'
iv_body = |! ! ! { iv_text } ! ! !| ).
mo_channel->send( iv_to = iv_to iv_subject = 'Re: [URGENT]' iv_body = 'Повторне' ).
ENDMETHOD.
ENDCLASS.

Використання:

" urgent email
DATA(lo_1) = NEW zcl_notification_urgent( io_channel = NEW zcl_channel_email( ) ).
lo_1->send( iv_to = 'admin@company.com' iv_text = 'Server down' ).
" normal telegram
DATA(lo_2) = NEW zcl_notification_normal( io_channel = NEW zcl_channel_telegram( ) ).
lo_2->send( iv_to = '@chat_id' iv_text = 'Report ready' ).

Нова реалізація (WhatsApp, Slack) — новий клас каналу, жодна зміна у ієрархії notification. Новий тип сповіщення (warning) — один клас, працює з усіма каналами.

  • CL_BCS_MESSAGE + cl_document_bcs — SAP робить bridge: повідомлення (документ) окремо, спосіб відправки (email/fax/print) — окремо.
  • Persistence Service (cl_os_state) + class persistence — розділення класу сутності від способу зберігання.
  • Printing Architecture — логічні принтери (device types) як реалізація, документ як абстракція.
  • Не плутай з простим DI. Якщо в класі просто є io_dependency TYPE REF TO zif_foo — це ще не Bridge, це просто залежність. Bridge — про дві ієрархії, що розвиваються незалежно.
  • Передчасне ускладнення. Якщо реалізація одна і ніколи не буде двох — Bridge додає шар без вигоди. Чекай доки не зʼявиться друга реалізація.
  • Обовʼязки замазані. Чітко визнач: що робить абстракція (логіка типу повідомлення), а що — реалізація (механіка каналу). Інакше повториш код в обох ієрархіях.

Коли НЕ використовувати

Section titled “Коли НЕ використовувати”
  • Один вимір варіативності — бери Strategy або просто наслідування.
  • Два виміри, але невеликі (2×2=4 класи) — плоскі 4 класи зрозуміліші.
  • Варіативність фіксована — бери композицію без окремих ієрархій.