Метафора
Метафора данного паттерна явно следует из его названия. Представьте ситуацию, когда на стройке работает прораб (Director) и строители (Builder’ы). Строители умеют выполнять некоторые работы, которые необходимы, например, для кладки стены: положить на фундамент гидроизоляцию, замешать раствор, выложить кладку из кирпича. Однако сам строитель не знает технологического процесса который необходимо выполнить для того чтобы успешно построить стену. Для этого существует прораб, который благодаря своим знаниям и умениям строителя сможет организовать процесс создания стены. Кроме того, в нашем примере может быть ситуация, когда один строитель может строить одну стену, но совсем не понимает, как построить другую. Для этого начальник стройки (клиент) определяет каким строителем снабдить прораба для получения необходимого типа стены. В метафоре важно понимать, что процесс постройки любой стены унифицирован и имеет четко определенные шаги, а уже конкретный строитель знает, как реализовать эти шаги для создания нужного типа стены (продукта), а прораб контролирует выполнение шагов.
Назначение
Отделяет конструирование сложного объекта от его представления, так что в результате одного и того же процесса конструирования могут получаться разные представления. Паттерн подходит для ситуаций, когда процесс создания продукта является сложным и состоит из нескольких этапов, при этом одним клиентам нужны одни параметры создаваемого продукта, другим другие.
Диаграмма
Пример
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 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 |
PARAMETERS: p_list TYPE abap_bool RADIOBUTTON GROUP 1, p_gui TYPE abap_bool RADIOBUTTON GROUP 1. *&---------------------------------------------------------------------* *& Определение классов *&---------------------------------------------------------------------* CLASS lcl_alv_builder DEFINITION ABSTRACT. PUBLIC SECTION. METHODS: setup_display_options ABSTRACT , setup_functions ABSTRACT , get_alv RETURNING value(ro_alv) TYPE REF TO cl_salv_table. PROTECTED SECTION. DATA: mo_alv TYPE REF TO cl_salv_table. ENDCLASS. "lcl_alv_builder DEFINITION CLASS lcl_list_alv_builder DEFINITION INHERITING FROM lcl_alv_builder. PUBLIC SECTION. METHODS: constructor IMPORTING ir_table TYPE REF TO data, setup_display_options REDEFINITION, setup_functions REDEFINITION. ENDCLASS. "lcl_list_alv_builder DEFINITION CLASS lcl_gui_alv_builder DEFINITION INHERITING FROM lcl_alv_builder. PUBLIC SECTION. METHODS: constructor IMPORTING ir_table TYPE REF TO data, setup_display_options REDEFINITION, setup_functions REDEFINITION. ENDCLASS. "lcl_gui_alv_builder DEFINITION CLASS lcl_alv_maker DEFINITION. PUBLIC SECTION. METHODS: constructor IMPORTING io_alv_builder TYPE REF TO lcl_alv_builder, construct_alv RETURNING VALUE(ro_alv) TYPE REF TO cl_salv_table. PRIVATE SECTION. DATA: mo_builder TYPE REF TO lcl_alv_builder. ENDCLASS. *&---------------------------------------------------------------------* *& Реализация классов *&---------------------------------------------------------------------* CLASS lcl_alv_builder IMPLEMENTATION. METHOD get_alv. ro_alv = mo_alv. ENDMETHOD. "get_alv ENDCLASS. "lcl_alv_builder IMPLEMENTATION CLASS lcl_list_alv_builder IMPLEMENTATION. METHOD constructor. FIELD-SYMBOLS: <lt_table> TYPE table. super->constructor( ). ASSIGN ir_table->* TO <lt_table>. CHECK sy-subrc EQ 0. TRY. cl_salv_table=>factory( EXPORTING list_display = if_salv_c_bool_sap=>true IMPORTING r_salv_table = mo_alv CHANGING t_table = <lt_table> ). CATCH cx_salv_msg. ENDTRY. ENDMETHOD. "constructor METHOD setup_display_options. " Определение настроек отображения специфичных для списка ENDMETHOD. "setup_display_options METHOD setup_functions. " Определение настроек функций для списка ENDMETHOD. "setup_functions ENDCLASS. "lcl_list_alv_builder IMPLEMENTATION CLASS lcl_gui_alv_builder IMPLEMENTATION. METHOD constructor. FIELD-SYMBOLS: <lt_table> TYPE table. super->constructor( ). ASSIGN ir_table->* TO <lt_table>. CHECK sy-subrc EQ 0. TRY. cl_salv_table=>factory( EXPORTING list_display = if_salv_c_bool_sap=>false IMPORTING r_salv_table = mo_alv CHANGING t_table = <lt_table> ). CATCH cx_salv_msg. ENDTRY. ENDMETHOD. "constructor METHOD setup_display_options. " Определение настроек отображения специфичных для gui alv ENDMETHOD. "setup_display_options METHOD setup_functions. " Определение настроек функций для gui alv ENDMETHOD. "setup_functions ENDCLASS. "lcl_gui_alv_builder IMPLEMENTATION CLASS lcl_alv_maker IMPLEMENTATION. METHOD constructor. mo_builder = io_alv_builder. ENDMETHOD. METHOD construct_alv. mo_builder->setup_display_options( ). mo_builder->setup_functions( ). ro_alv = mo_builder->get_alv( ). ENDMETHOD. ENDCLASS. *&---------------------------------------------------------------------* *& Работа с объектами *&---------------------------------------------------------------------* START-OF-SELECTION. DATA: lo_alv_maker TYPE REF TO lcl_alv_maker, lo_alv_builder TYPE REF TO lcl_alv_builder, lt_table TYPE TABLE OF spfli, lr_table TYPE REF TO data. SELECT * FROM spfli INTO CORRESPONDING FIELDS OF TABLE lt_table. GET REFERENCE OF lt_table INTO lr_table. CASE abap_true. WHEN p_list. CREATE OBJECT lo_alv_builder TYPE lcl_list_alv_builder EXPORTING ir_table = lr_table. WHEN p_gui. CREATE OBJECT lo_alv_builder TYPE lcl_gui_alv_builder EXPORTING ir_table = lr_table. ENDCASE. CREATE OBJECT lo_alv_maker EXPORTING io_alv_builder = lo_alv_builder. lo_alv_maker->construct_alv( )->display( ). |
В примере реализовано несколько классов строителей, которые создают либо ALV в виде списка, либо в виде грида. Управляет последовательностью операций по созданию ALV класс-директор – lcl_alv_maker. В зависимости от параметров с экрана выбора, класс-директор компонуется либо одним строителем, либо другим.
На практике очень часто используется упрощенная схема данного паттерна, т.к. возможность создания разнообразных продуктов нужна относительно редко, и возрастающая при этом сложность не всегда окупается.
Диаграмма упрощённой реализации:
Пример:
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 |
CLASS lcl_product DEFINITION. PUBLIC SECTION. DATA: mv_header TYPE string, mv_footer TYPE string, mv_text TYPE string. METHODS: write. ENDCLASS. CLASS lcl_product IMPLEMENTATION. METHOD write. WRITE: / 'HDR:', mv_header, 'FTR:', mv_footer, 'TXT:', mv_text. ENDMETHOD. ENDCLASS. CLASS lcl_builder DEFINITION. PUBLIC SECTION. METHODS: init_product RETURNING VALUE(ro_builder) TYPE REF TO lcl_builder, set_header IMPORTING iv_header TYPE string RETURNING VALUE(ro_builder) TYPE REF TO lcl_builder, set_footer IMPORTING iv_footer TYPE string RETURNING VALUE(ro_builder) TYPE REF TO lcl_builder, set_text IMPORTING iv_text TYPE string RETURNING VALUE(ro_builder) TYPE REF TO lcl_builder, get_product RETURNING VALUE(ro_product) TYPE REF TO lcl_product. PRIVATE SECTION. DATA: mo_product TYPE REF TO lcl_product. ENDCLASS. CLASS lcl_builder IMPLEMENTATION. METHOD init_product. CREATE OBJECT mo_product. ro_builder = me. ENDMETHOD. METHOD set_header. IF mo_product IS NOT BOUND. init_product( ). ENDIF. mo_product->mv_header = iv_header. ro_builder = me. ENDMETHOD. METHOD set_footer. IF mo_product IS NOT BOUND. init_product( ). ENDIF. mo_product->mv_footer = iv_footer. ro_builder = me. ENDMETHOD. METHOD set_text. IF mo_product IS NOT BOUND. init_product( ). ENDIF. mo_product->mv_text = iv_text. ro_builder = me. ENDMETHOD. METHOD get_product. ro_product = mo_product. ENDMETHOD. ENDCLASS. START-OF-SELECTION. DATA: lo_product TYPE REF TO lcl_product, lo_builer TYPE REF TO lcl_builder. CREATE OBJECT lo_builer. lo_product = lo_builer->set_footer( 'Footer1' )->set_header( 'Header 1' )->set_text( 'Text 1' )->get_product( ). lo_product->write( ). lo_product = lo_builer->init_product( )->set_footer( 'Footer2' )->set_header( 'Header 2' )->set_text( 'Text 2' )->get_product( ). lo_product->write( ). |
В данном примере мы предоставили клиенту интерфейс по созданию некоторого продукта, при этом клиент сам определяет каким образом его создать, какие операции использовать.