ABAP面向对象之建造者模式(Builder Pattern)
根据定义,将复杂对象的创建与其表示分开。这将允许您重用相同的构造过程来创建同一对象的不同表示。换句话说,Builder 通过一步一步的过程来创建对象。它还解耦了对象的创建方式,因此相同的设置可以创建对象的不同表示。
您可能会想它与我们之前讨论的抽象工厂设计模式有何不同?抽象工厂通常会立即返回对象,因为 Builder 有复杂的逐步过程来为您构建对象。构建器首先实例化对象并遵循所有必要步骤以确保对象已准备好使用。
应用实例
1、去肯德基,汉堡、可乐、薯条、炸鸡翅等是不变的,而其组合是经常变化的,生成出所谓的"套餐"。 2、JAVA 中的 StringBuilder。
优点
1、建造者独立,易扩展。2、便于控制细节风险。
缺点
1、产品必须有共同点,范围有限制。 2、如内部变化复杂,会有很多的建造类。
使用场景
1、需要生成的对象具有复杂的内部结构。 2、需要生成的对象内部属性本身相互依赖。 注意事项:与工厂模式的区别是:建造者模式更加关注与零件装配的顺序。
实现
我们假设一个披萨店的商业案例,其中,一个典型的套餐可以是一个披萨(Pizza)和一杯冷饮(Cold drink)。披萨(Pizza)可以是素食披萨(Veg Pizza)或芝士披萨(Cheese Pizza),它们是包在纸盒中。冷饮(Cold drink)可以是可口可乐(coke)或百事可乐(pepsi),它们是装在瓶子中。 我们将创建一个表示食物条目(比如披萨和冷饮)的 Item 接口和实现 Item 接口的实体类,以及一个表示食物包装的 Packing 接口和实现 Packing 接口的实体类,披萨是包在纸盒中,冷饮是装在瓶子中。 然后我们创建一个 Meal 类,带有 Item 的 List 和一个通过结合 Item 来创建不同类型的 Meal 对象的 MealBuilder。BuilderPatternDemo 类使用 MealBuilder 来创建一个 Meal。
UML

- 创建一个表示食物条目和食物包装的接口。
INTERFACE if_packing. METHODS pack RETURNING VALUE(rv_name) TYPE string. ENDINTERFACE. INTERFACE if_item. METHODS:name RETURNING VALUE(rv_name) TYPE string, packing RETURNING VALUE(ro_packing) TYPE REF TO if_packing, price RETURNING VALUE(rv_price) TYPE price. ENDINTERFACE.
- 创建实现 Packing 接口的实体类。
CLASS cl_wrapper DEFINITION. PUBLIC SECTION. INTERFACES if_packing. ENDCLASS. CLASS cl_wrapper IMPLEMENTATION. METHOD if_packing~pack. rv_name = 'Wrapper'. ENDMETHOD. ENDCLASS. CLASS cl_bottle DEFINITION. PUBLIC SECTION. INTERFACES if_packing. ENDCLASS. CLASS cl_bottle IMPLEMENTATION. METHOD if_packing~pack. rv_name = 'Bottle'. ENDMETHOD. ENDCLASS.
- 创建实现 Item 接口的抽象类,该类提供了默认的功能。
CLASS cl_pizza DEFINITION ABSTRACT. PUBLIC SECTION. INTERFACES if_item. ENDCLASS. CLASS cl_pizza IMPLEMENTATION. METHOD if_item~packing. ro_packing = NEW cl_wrapper( ). ENDMETHOD. METHOD if_item~name. ENDMETHOD. METHOD if_item~price. ENDMETHOD. ENDCLASS. CLASS cl_cold_drink DEFINITION ABSTRACT. PUBLIC SECTION. INTERFACES if_item. ENDCLASS. CLASS cl_cold_drink IMPLEMENTATION. METHOD if_item~packing. ro_packing = NEW cl_bottle( ). ENDMETHOD. METHOD if_item~name. ENDMETHOD. METHOD if_item~price. ENDMETHOD. ENDCLASS.
- 创建扩展了 CL_Pizza 和 cl_Cold_Drink 的实体类。
CLASS cl_veg_pizza DEFINITION INHERITING FROM cl_pizza. PUBLIC SECTION. METHODS if_item~name REDEFINITION. METHODS if_item~price REDEFINITION. ENDCLASS. CLASS cl_veg_pizza IMPLEMENTATION. METHOD if_item~name. rv_name = 'Veg Pizza'. ENDMETHOD. METHOD if_item~price. rv_price = 11. ENDMETHOD. ENDCLASS. CLASS cl_cheese_pizza DEFINITION INHERITING FROM cl_pizza. PUBLIC SECTION. METHODS if_item~name REDEFINITION. METHODS if_item~price REDEFINITION. ENDCLASS. CLASS cl_cheese_pizza IMPLEMENTATION. METHOD if_item~name. rv_name = 'Cheese Pizza'. ENDMETHOD. METHOD if_item~price. rv_price = 28. ENDMETHOD. ENDCLASS. CLASS cl_coke DEFINITION INHERITING FROM cl_cold_drink. PUBLIC SECTION. METHODS if_item~name REDEFINITION. METHODS if_item~price REDEFINITION. ENDCLASS. CLASS cl_coke IMPLEMENTATION. METHOD if_item~name. rv_name = 'Coke'. ENDMETHOD. METHOD if_item~price. rv_price = 3. ENDMETHOD. ENDCLASS. CLASS cl_pepsi DEFINITION INHERITING FROM cl_cold_drink. PUBLIC SECTION. METHODS if_item~name REDEFINITION. METHODS if_item~price REDEFINITION. ENDCLASS. CLASS cl_pepsi IMPLEMENTATION. METHOD if_item~name. rv_name = 'Pepsi'. ENDMETHOD. METHOD if_item~price. rv_price = 4. ENDMETHOD. ENDCLASS.
5.创建一个 CL_Meal 类,带有上面定义的 Item 对象
CLASS cl_meal DEFINITION. PUBLIC SECTION. METHODS: add_item IMPORTING iv_item TYPE REF TO if_item, get_price RETURNING VALUE(rv_price) TYPE price, show_items . PRIVATE SECTION. TYPES:BEGIN OF ty_item, item TYPE REF TO if_item, END OF ty_item. DATA:gt_item TYPE TABLE OF ty_item. ENDCLASS. CLASS cl_meal IMPLEMENTATION. METHOD: add_item. APPEND VALUE #( item = iv_item ) TO gt_item. ENDMETHOD. METHOD: get_price. LOOP AT gt_item ASSIGNING FIELD-SYMBOL(<lo_item>). DATA(lv_price) = <lo_item>-item->price( ). rv_price = lv_price + rv_price. ENDLOOP. ENDMETHOD. METHOD: show_items. LOOP AT gt_item ASSIGNING FIELD-SYMBOL(<lo_item>). WRITE:/ 'Item :', <lo_item>-item->name( ). WRITE:/ 'Packing :',<lo_item>-item->packing( )->pack( ) . WRITE:/ 'Price :', <lo_item>-item->price( ). ENDLOOP. ENDMETHOD. ENDCLASS.
6.创建一个 CL_Meal_Builder 类,实际的 cl_builder 类负责创建 cl_Meal 对象。
CLASS cl_meal_builder DEFINITION. PUBLIC SECTION. METHODS:prepare_veg_meal RETURNING VALUE(ro_meal) TYPE REF TO cl_meal. METHODS:prepare_cheese_meal RETURNING VALUE(ro_meal) TYPE REF TO cl_meal. ENDCLASS. CLASS cl_meal_builder IMPLEMENTATION. METHOD prepare_veg_meal. ro_meal = NEW cl_meal( ). ro_meal->add_item( NEW cl_veg_pizza( ) ). ro_meal->add_item( NEW cl_coke( ) ). ENDMETHOD. METHOD prepare_cheese_meal. ro_meal = NEW cl_meal( ). ro_meal->add_item( NEW cl_cheese_pizza( ) ). ro_meal->add_item( NEW cl_pepsi( ) ). ENDMETHOD. ENDCLASS.
7.cl_application 使用 cl_Meal_Builder 来演示建造者模式(Builder Pattern)。
CLASS cl_application DEFINITION. PUBLIC SECTION. CLASS-METHODS: run . ENDCLASS. CLASS cl_application IMPLEMENTATION. METHOD run. DATA(lo_meal_builder) = NEW cl_meal_builder( ). DATA(lo_veg_meal) = lo_meal_builder->prepare_veg_meal( ). WRITE:/ '--------------------------'. WRITE:/ '>>>Veg Meal'. WRITE:/ '--------------------------'. lo_veg_meal->show_items( ). WRITE:/ 'Total Cost: ', lo_veg_meal->get_price( ). DATA(lo_chees_meal) = lo_meal_builder->prepare_cheese_meal( ). WRITE:/ '--------------------------'. WRITE:/ '>>>Cheese Meal' . WRITE:/ '--------------------------'. lo_chees_meal->show_items( ). WRITE:/ 'Total Cost: ', lo_chees_meal->get_price( ). ENDMETHOD. ENDCLASS. START-OF-SELECTION. cl_application=>run( ).
8.执行程序,输出结果:
