Command
Command — поведінковий патерн: запит на дію стає обʼєктом. Обʼєкт тримає посилання на одержувача (receiver) та параметри виклику, і має єдиний метод execute( ). Це відкриває можливості: ставити команди в чергу, логувати, повторювати, відкочувати (undo), транспортувати через мережу.
Метафора
Section titled “Метафора”Кнопка вмикача світла. Сама кнопка не знає, що саме увімкне — лампу, вентилятор чи двигун. Вона просто «натискає» — і десь вдалині виконується дія. Заміна пристрою — не потребує зміни кнопки.
Коли застосовувати
Section titled “Коли застосовувати”- UI-меню/тулбар, де кнопка не повинна знати бізнес-логіку — вона просто тригерить команду.
- Треба undo/redo — зберігаєш стек виконаних команд з можливістю відкату.
- Команди потрібно серіалізувати (журнал транзакцій, queue для асинхронного виконання).
- Треба лог виконаних операцій або повтор одної дії на різних обʼєктах.
- Макроси: послідовність команд як одна композитна команда.
ABAP-реалізація
Section titled “ABAP-реалізація”" Контракт командиINTERFACE zif_command. METHODS: execute, undo.ENDINTERFACE.
" Receiver — справжній виконавецьCLASS zcl_order DEFINITION PUBLIC FINAL CREATE PUBLIC. PUBLIC SECTION. METHODS: add_item IMPORTING iv_matnr TYPE matnr iv_qty TYPE p, remove_item IMPORTING iv_matnr TYPE matnr iv_qty TYPE p.ENDCLASS.
" Конкретна команда — тримає receiver і параметриCLASS zcl_cmd_add_item DEFINITION PUBLIC FINAL CREATE PUBLIC. PUBLIC SECTION. INTERFACES zif_command. METHODS constructor IMPORTING io_order TYPE REF TO zcl_order iv_matnr TYPE matnr iv_qty TYPE p. PRIVATE SECTION. DATA: mo_order TYPE REF TO zcl_order, mv_matnr TYPE matnr, mv_qty TYPE p.ENDCLASS.
CLASS zcl_cmd_add_item IMPLEMENTATION. METHOD constructor. mo_order = io_order. mv_matnr = iv_matnr. mv_qty = iv_qty. ENDMETHOD. METHOD zif_command~execute. mo_order->add_item( iv_matnr = mv_matnr iv_qty = mv_qty ). ENDMETHOD. METHOD zif_command~undo. mo_order->remove_item( iv_matnr = mv_matnr iv_qty = mv_qty ). ENDMETHOD.ENDCLASS.
" Invoker — запускає, не знає конкретної командиCLASS zcl_cmd_invoker DEFINITION PUBLIC FINAL CREATE PUBLIC. PUBLIC SECTION. METHODS: execute IMPORTING io_command TYPE REF TO zif_command, undo_last. PRIVATE SECTION. DATA mt_history TYPE STANDARD TABLE OF REF TO zif_command WITH EMPTY KEY.ENDCLASS.
CLASS zcl_cmd_invoker IMPLEMENTATION. METHOD execute. io_command->execute( ). APPEND io_command TO mt_history. ENDMETHOD. METHOD undo_last. DATA(lv_idx) = lines( mt_history ). CHECK lv_idx > 0. READ TABLE mt_history INDEX lv_idx INTO DATA(lo_last). lo_last->undo( ). DELETE mt_history INDEX lv_idx. ENDMETHOD.ENDCLASS.Використання:
DATA(lo_order) = NEW zcl_order( ).DATA(lo_invoker) = NEW zcl_cmd_invoker( ).
lo_invoker->execute( NEW zcl_cmd_add_item( io_order = lo_order iv_matnr = 'A1' iv_qty = 5 ) ).
lo_invoker->execute( NEW zcl_cmd_add_item( io_order = lo_order iv_matnr = 'A2' iv_qty = 3 ) ).
lo_invoker->undo_last( ). " відкочує додавання A2Macro Command — композиція
Section titled “Macro Command — композиція”Команда, що містить інші команди:
CLASS zcl_cmd_macro DEFINITION PUBLIC FINAL CREATE PUBLIC. PUBLIC SECTION. INTERFACES zif_command. METHODS add IMPORTING io_command TYPE REF TO zif_command. PRIVATE SECTION. DATA mt_commands TYPE STANDARD TABLE OF REF TO zif_command WITH EMPTY KEY.ENDCLASS.
CLASS zcl_cmd_macro IMPLEMENTATION. METHOD zif_command~execute. LOOP AT mt_commands INTO DATA(lo). lo->execute( ). ENDLOOP. ENDMETHOD. METHOD zif_command~undo. " undo — у зворотному порядку LOOP AT mt_commands INTO DATA(lo_cmd). ENDLOOP. DO lines( mt_commands ) TIMES. DATA(lv_idx) = lines( mt_commands ) - sy-index + 1. READ TABLE mt_commands INDEX lv_idx INTO lo_cmd. lo_cmd->undo( ). ENDDO. ENDMETHOD.ENDCLASS.SAP-специфіка
Section titled “SAP-специфіка”sy-ucommдиспетчер у класичних диналогах — наївна форма Command:CASE sy-ucomm WHEN 'SAVE'. WHEN 'DEL'.Але без обʼєктів — не можна undo, не можна логувати.- Update Tasks (
CALL FUNCTION ... IN UPDATE TASK) — рід асинхронних Command-ів на рівні ядра. - Workflow — event + step = фактично command у runtime-оркестрації.
Підводні камені
Section titled “Підводні камені”- Undo не завжди можливий. Якщо команда мала побічний ефект (RFC-виклик, email, друк) — відкат — це інша команда, не просто зворотна дія. Іноді undo взагалі неможливий.
- Стан у команді. Команда тримає параметри і receiver. Якщо receiver довгоживучий, а команда потрібна тільки для одного виконання — не тримай історію довше, ніж треба. Витоки.
- Серіалізація. Якщо треба зберігати команди у БД (для later replay або audit) — команда не може містити обʼєкти без контракту серіалізації. Пакуй параметри у DTO-структури.
- Перетягування логіки. Команда має координувати дію на receiver-і, а не містити всю бізнес-логіку. Інакше receiver стає анемічним, а команда — богом.
Коли НЕ використовувати
Section titled “Коли НЕ використовувати”- Просто виклик методу — не роби навколо нього команду-обʼєкт.
- Undo не потрібен, логування не потрібне, черги нема. Без цих юз-кейсів Command — overkill.
- Перформанс-критичний код у тісному циклі — створення обʼєкта на кожну дію додає витрат.