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

Template Method

Template Method — поведінковий патерн: скелет алгоритму фіксується у базовому (абстрактному) класі, а окремі його кроки — винесені в абстрактні методи, які реалізують нащадки. Послідовність кроків — незмінна.

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

  • Алгоритм має чітку послідовність кроків, а варіативна лише реалізація окремих.
  • Дублюєшся в кількох класах одним і тим самим каркасом, тільки окремі рядки різні.
  • Треба зафіксувати інваріант процесу: завжди спочатку валідація, потім виконання, потім комміт.
CLASS zcl_report_base DEFINITION PUBLIC ABSTRACT.
PUBLIC SECTION.
METHODS run FINAL. " скелет — не переозначуваний
PROTECTED SECTION.
METHODS:
load ABSTRACT, " кожен нащадок по-своєму
compute ABSTRACT,
render ABSTRACT.
" hook — за замовчуванням нічого не робить, нащадок може переозначити
METHODS on_before_load.
ENDCLASS.
CLASS zcl_report_base IMPLEMENTATION.
METHOD run.
on_before_load( ). " hook
load( ).
compute( ).
render( ).
ENDMETHOD.
METHOD on_before_load.
RETURN. " порожній дефолт
ENDMETHOD.
ENDCLASS.
" Нащадок переозначає тільки кроки
CLASS zcl_report_sales DEFINITION PUBLIC FINAL INHERITING FROM zcl_report_base.
PROTECTED SECTION.
METHODS:
load REDEFINITION,
compute REDEFINITION,
render REDEFINITION.
PRIVATE SECTION.
DATA mt_sales TYPE STANDARD TABLE OF vbak.
ENDCLASS.
CLASS zcl_report_sales IMPLEMENTATION.
METHOD load. SELECT * FROM vbak INTO TABLE @mt_sales UP TO 1000 ROWS. ENDMETHOD.
METHOD compute. " агрегація ... ENDMETHOD.
METHOD render. " вивід ... ENDMETHOD.
ENDCLASS.

КлючовеMETHODS run FINAL: скелет заборонено переозначувати. Нащадок може лише заповнювати кроки, не ламати порядок.

Hooks — опційні точки розширення

Section titled “Hooks — опційні точки розширення”

Якщо крок потрібен не всім нащадкам — зроби його НЕ ABSTRACT, з порожньою реалізацією у базовому класі. Нащадок перевизначить за потреби.

METHOD run.
on_before_load( ). " опційний hook
load( ).
IF needs_compute( ).
compute( ).
ENDIF.
render( ).
ENDMETHOD.

Don't call us, we'll call you — характерна фраза Template Method. Нащадок не викликає базовий клас, а реалізує кроки. Базовий клас сам викликає нащадка у потрібному місці. Це відрізняє Template Method від звичайного наслідування з super->run( ).

  • BAdI implementation — класичний Template Method зсередини SAP: SAP-код виконує процес, BAdI-методи — «кроки», які замовник заповнює.
  • RAP behavior implementation — саме за цим патерном: RAP-фреймворк викликає modify, read, validate, determine у певному порядку, розробник реалізує окремі методи.
  • cl_abap_unit_assert — не template method, але CLASS ... FOR TESTING ... + setup/teardown/test* — так, framework викликає їх у фіксованому порядку.
Template MethodStrategy
МеханізмНаслідуванняКомпозиція (інтерфейс + поле)
Зміна варіантівНа етапі компіляції (новий клас)У runtime (підміна обʼєкта)
Кількість варіаційОдна — через підкласБагато одночасно
Ступінь гнучкостіФіксований скелетВільніший — весь алгоритм інкапсульовано

Сьогодні композиція переважає (Clean ABAP). Якщо треба підмінити логіку у runtime — бери Strategy. Template Method — коли ієрархія природна і варіацій класу одиниці.

  • Скелет не має бути ENDMETHOD-тупіковим. Нащадок не може розширити послідовність, тільки заповнити кроки. Якщо треба додати новий крок — треба правити базовий клас. Буває незручно.
  • run FINAL обовʼязково. Якщо нащадок переозначить run( ) — весь патерн ламається, інваріант послідовності зникає.
  • Надмірне наслідування. Якщо варіацій кроків багато — ієрархія стає глибокою. Часто краще винести варіативні кроки у Strategy-обʼєкти, які передаються через конструктор.
  • Приховані залежності між кроками. Якщо compute( ) неявно покладається на те, що load( ) заповнив mt_data — це крихке. Краще передавати дані між кроками через RETURNING або явні DATA-поля з contract-ом у документації.

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

Section titled “Коли НЕ використовувати”
  • Варіацій більше однієї на момент виконання — бери Strategy.
  • Скелет не стабільний — часто додаєш/прибираєш кроки.
  • Нащадки розрізняються не тільки реалізацією, а й послідовністю — Template Method тут не зайде.