Factory Method
Factory Method — породжуючий патерн: створення конкретного класу інкапсульовано в окремому методі, а клієнт отримує обʼєкт через інтерфейс або абстрактний базовий клас. Вибір конкретного класу залежить від параметра.
Метафора
Section titled “Метафора”Логістична компанія дає клієнту «транспорт». Чи це буде фура, вагон, чи баржа — вирішує диспетчер на основі маршруту і ваги. Клієнт про це не знає — він просто завантажує вантаж.
Коли застосовувати
Section titled “Коли застосовувати”- У клієнта має бути один контракт на сімейство реалізацій (парсери, експортери, калькулятори знижок).
- Конкретний клас обирається на основі вхідних даних (формат файлу, тип обʼєкта, customizing-параметр).
- Не хочеш розмазувати
CASEпо всьому коду — він збирається в одному місці у фабриці.
ABAP-реалізація
Section titled “ABAP-реалізація”Рекомендована форма — окремий клас-фабрика з CLASS-METHOD create. Альтернатива — статичний метод у базовому класі, але це змішує дві відповідальності (поведінка + побудова).
INTERFACE zif_report_writer. METHODS write IMPORTING it_data TYPE REF TO data RAISING zcx_writer_error.ENDINTERFACE.
CLASS zcl_alv_writer DEFINITION PUBLIC FINAL CREATE PRIVATE. PUBLIC SECTION. INTERFACES zif_report_writer.ENDCLASS.
CLASS zcl_pdf_writer DEFINITION PUBLIC FINAL CREATE PRIVATE. PUBLIC SECTION. INTERFACES zif_report_writer.ENDCLASS.
CLASS zcl_xlsx_writer DEFINITION PUBLIC FINAL CREATE PRIVATE. PUBLIC SECTION. INTERFACES zif_report_writer.ENDCLASS.
CLASS zcl_writer_factory DEFINITION PUBLIC FINAL CREATE PUBLIC. PUBLIC SECTION. TYPES ty_format TYPE c LENGTH 4. CONSTANTS: mc_alv TYPE ty_format VALUE 'ALV', mc_pdf TYPE ty_format VALUE 'PDF', mc_xlsx TYPE ty_format VALUE 'XLSX'.
CLASS-METHODS create IMPORTING iv_format TYPE ty_format RETURNING VALUE(ro_writer) TYPE REF TO zif_report_writer RAISING zcx_unknown_format.ENDCLASS.
CLASS zcl_writer_factory IMPLEMENTATION. METHOD create. CASE iv_format. WHEN mc_alv. ro_writer = NEW zcl_alv_writer( ). WHEN mc_pdf. ro_writer = NEW zcl_pdf_writer( ). WHEN mc_xlsx. ro_writer = NEW zcl_xlsx_writer( ). WHEN OTHERS. RAISE EXCEPTION NEW zcx_unknown_format( iv_format = iv_format ). ENDCASE. ENDMETHOD.ENDCLASS.Конкретні класи зроблені CREATE PRIVATE + FRIENDS zcl_writer_factory — інстансувати їх може тільки фабрика. Це захищає контракт: клієнт не створить zcl_alv_writer( ) повз фабрику і не оминатиме валідацію формату.
Використання:
DATA(lo_writer) = zcl_writer_factory=>create( zcl_writer_factory=>mc_pdf ).lo_writer->write( REF #( mt_alv ) ).Варіант із «поліморфним конструктором» у базовому класі
Section titled “Варіант із «поліморфним конструктором» у базовому класі”Коли новий тип додається рідко, а ієрархія вже є — допустимо:
CLASS lcl_base_writer DEFINITION ABSTRACT. PUBLIC SECTION. CLASS-METHODS get_writer IMPORTING iv_format TYPE string RETURNING VALUE(ro_writer) TYPE REF TO lcl_base_writer. METHODS write ABSTRACT.ENDCLASS.Недолік: базовий клас знає про всіх своїх нащадків — порушує відкритість/закритість. Для production-коду — краще окрема фабрика.
SAP-специфіка
Section titled “SAP-специфіка”cl_salv_table=>factory( )— канонічний приклад factory method у SAP-стандарті: клієнт отримуєcl_salv_table, SAP всередині обирає правильну реалізацію.cl_abap_typedescr=>describe_by_*( )— фабрикаCL_ABAP_*DESCRобʼєктів (кастомна з залежністю від типу).- BAdI через
cl_badi_manager=>get_badi_ref( )— теж factory-like.
Підводні камені
Section titled “Підводні камені”- Перегрузка параметрами. Якщо різні конкретні класи вимагають принципово різних параметрів — не ліпи все в один
create. Зроби кілька іменованих методів:create_from_file( ),create_from_itab( ),create_from_url( ). - Невідомий тип = exception, не
null. Ніколи не повертайro_writer = NULLмовчки — кидайZCX_UNKNOWN_FORMAT. - Абстрактний базовий клас. Якщо використовуєш варіант із методом у базовому класі — зроби його
ABSTRACT, щоб випадково не створилиNEW lcl_base_writer( ). - Не плутай з Abstract Factory. Factory Method створює один тип продукту; Abstract Factory — сімейство повʼязаних продуктів одразу.
Коли НЕ використовувати
Section titled “Коли НЕ використовувати”- Один клас без альтернатив — просто
NEW zcl_foo( ). Не роби фабрику на майбутнє. - Коли відмінності між «варіантами» — це просто різні значення параметра. Тоді вистачить
NEW zcl_foo( iv_mode = 'A' ).