Template Method
Template Method — поведінковий патерн: скелет алгоритму фіксується у базовому (абстрактному) класі, а окремі його кроки — винесені в абстрактні методи, які реалізують нащадки. Послідовність кроків — незмінна.
Метафора
Section titled “Метафора”Рецепт завтрака в готелі: нагріти, обсмажити, подати. Послідовність однакова, але «що саме нагріти» (яєчня, омлет, млинці) — вирішує кожна кухня. Клієнт каже «сніданок», отримує блюдо, бо скелет процесу стандартний.
Коли застосовувати
Section titled “Коли застосовувати”- Алгоритм має чітку послідовність кроків, а варіативна лише реалізація окремих.
- Дублюєшся в кількох класах одним і тим самим каркасом, тільки окремі рядки різні.
- Треба зафіксувати інваріант процесу: завжди спочатку валідація, потім виконання, потім комміт.
ABAP-реалізація
Section titled “ABAP-реалізація”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.Hollywood Principle
Section titled “Hollywood Principle”Don't call us, we'll call you — характерна фраза Template Method. Нащадок не викликає базовий клас, а реалізує кроки. Базовий клас сам викликає нащадка у потрібному місці. Це відрізняє Template Method від звичайного наслідування з super->run( ).
SAP-специфіка
Section titled “SAP-специфіка”- 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 Method vs Strategy
Section titled “Template Method vs Strategy”| Template Method | Strategy | |
|---|---|---|
| Механізм | Наслідування | Композиція (інтерфейс + поле) |
| Зміна варіантів | На етапі компіляції (новий клас) | У runtime (підміна обʼєкта) |
| Кількість варіацій | Одна — через підклас | Багато одночасно |
| Ступінь гнучкості | Фіксований скелет | Вільніший — весь алгоритм інкапсульовано |
Сьогодні композиція переважає (Clean ABAP). Якщо треба підмінити логіку у runtime — бери Strategy. Template Method — коли ієрархія природна і варіацій класу одиниці.
Підводні камені
Section titled “Підводні камені”- Скелет не має бути
ENDMETHOD-тупіковим. Нащадок не може розширити послідовність, тільки заповнити кроки. Якщо треба додати новий крок — треба правити базовий клас. Буває незручно. run FINALобовʼязково. Якщо нащадок переозначитьrun( )— весь патерн ламається, інваріант послідовності зникає.- Надмірне наслідування. Якщо варіацій кроків багато — ієрархія стає глибокою. Часто краще винести варіативні кроки у Strategy-обʼєкти, які передаються через конструктор.
- Приховані залежності між кроками. Якщо
compute( )неявно покладається на те, щоload( )заповнивmt_data— це крихке. Краще передавати дані між кроками черезRETURNINGабо явні DATA-поля з contract-ом у документації.
Коли НЕ використовувати
Section titled “Коли НЕ використовувати”- Варіацій більше однієї на момент виконання — бери Strategy.
- Скелет не стабільний — часто додаєш/прибираєш кроки.
- Нащадки розрізняються не тільки реалізацією, а й послідовністю — Template Method тут не зайде.