Назначение
Шаблонный метод определяет основу алгоритма (каркас) и позволяет подклассам переопределять некоторые шаги алгоритма, не изменяя его структуры в целом. Таким образом, контракт между базовым классом и его наследниками определяется более чётко, чем это делается простым наследованием. За счёт определения каркаса алгоритма в базовом классе, мы избегаем лишнего дублирования кода.
Диаграмма
Пример
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
*&---------------------------------------------------------------------* *& Определение классов/интерфейсов *&---------------------------------------------------------------------* CLASS lcl_template_discount DEFINITION ABSTRACT. PUBLIC SECTION. METHODS: calc_discount IMPORTING iv_product TYPE string iv_customer TYPE string RETURNING VALUE(rv_discount) TYPE i. PROTECTED SECTION. METHODS: calc_product_discount ABSTRACT IMPORTING iv_product TYPE string RETURNING VALUE(rv_discount) TYPE i, calc_customer_discount ABSTRACT IMPORTING iv_customer TYPE string RETURNING VALUE(rv_discount) TYPE i. ENDCLASS. CLASS lcl_workday_discount DEFINITION INHERITING FROM lcl_template_discount. PROTECTED SECTION. METHODS: calc_customer_discount REDEFINITION, calc_product_discount REDEFINITION. ENDCLASS. *&---------------------------------------------------------------------* *& Реализация классов *&---------------------------------------------------------------------* CLASS lcl_template_discount IMPLEMENTATION. METHOD calc_discount. DATA: lv_product_discount TYPE i, lv_customer_discount TYPE i. " Каркас алгоритма определяет шаги расчёта скидки относительно продукта и покупателя " после чего, выбирает наибольшую скидку. lv_product_discount = calc_product_discount( iv_product = iv_product ). lv_customer_discount = calc_customer_discount( iv_customer = iv_customer ). IF lv_product_discount > lv_customer_discount. rv_discount = lv_product_discount. ELSE. rv_discount = lv_customer_discount. ENDIF. ENDMETHOD. ENDCLASS. CLASS lcl_workday_discount IMPLEMENTATION. METHOD calc_customer_discount. CASE iv_customer. WHEN 'John'. rv_discount = 10. WHEN OTHERS. rv_discount = 5. ENDCASE. ENDMETHOD. METHOD calc_product_discount. CASE iv_product. WHEN 'Milk'. rv_discount = 10. WHEN OTHERS. rv_discount = 5. ENDCASE. ENDMETHOD. ENDCLASS. *&---------------------------------------------------------------------* *& Работа с шаблоном *&---------------------------------------------------------------------* START-OF-SELECTION. DATA: lo_discounter TYPE REF TO lcl_template_discount, lv_discount TYPE i. CREATE OBJECT lo_discounter TYPE lcl_workday_discount. lv_discount = lo_discounter->calc_discount( iv_product = 'Milk' iv_customer = 'John' ). WRITE lv_discount. |
В примере представлен шаблонный метод расчёта скидки по двум показателям: скидка по продукту и скидка по покупателю, большая из них идет в расчёт. Конкретный класс расчёта скидки реализует определенные в каркасе методы расчёта скидок, а клиент уже используя абстракцию, получает размер скидки.
К недостаткам применения данного паттерна можно отнести случай, когда требуется работа с конкретным наследником и его данными (методами, атрибутами) не определенными в базовом классе, соответственно клиент работает с конкретной реализацией и принцип OCP (SOLID) нарушается.