1.目的
将一个复杂对象的构建过程与它的表示分离,使得同样的构建过程,可以创建不同的表示。
2.解读
类比:
- 建造者模式类似于模拟现实世界中供应商和组装厂的关系。什么意思呢?举个栗子 😉
- 手机的生产过程其实就是一个很好的例子。一个手机“对象”是很复杂的,但如果不同的角色如果分工合作,扬长避短,那么就会极大降低手机生产的复杂度。也即,品牌厂商仅负责手机的设计工作,而手机的零件可以从不同的供应商采购,最终由代工厂完成手机组装。手机厂商、零件供应商和代工厂就是我们“建造者模式”的主角。
解析:
- 这个模式相对复杂,但不要被不同的角色所迷惑,“建造者模式” 的最终目的也是要产出一个类实例,只不过是将实例化的过程按照“职责”进行了进一步的分工
- 适用于复杂对象的构建,也即目标类的实例化过程很复杂
- 其实,一定程度上简化“建造者模式”的中角色也是可以的,划分不同角色,是为了更好地符合单一职责原则,并提升类的灵活性
各种角色:
- Product - 产品对象,也即我们最终想实例化的对象 (手机)
- Abstract Builder - 抽象建造者,为Product的形成提供各种部件方法(例如采购芯片、采购屏幕、采购电池等)
- Concrete Builder - 具体建造者,实现Abstract Builder,构造和装配各个具体的部件(例如,使用高通的芯片,夏普的屏幕,Sony的电池等等)
- Director - 指挥者,定义了建造的流程(例如先在主板上焊接芯片,然后连接屏幕,主板完成后,连接电池)
要点:
- “建造者模式” 的优点在于,其隐藏了某产品对象是如何组装的,若需要改变一个产品的内部表示,只需要在定义一个具体的建造者就可以了。
- 还是以手机的例子,如果生产另一种型号的手机,使用联发科芯片,京东方的屏幕,三星的电池,那么此时有另一个实现这些部件方法的建造者即可。手机的组装流程依然是标准的,也即先在焊接芯片,然后连接屏幕,最后连接电池。
- 由此可见,此模式适合这种对象内部构件的顺序稳定,但对象内部的表现有着复杂变化的对象
体现的设计原则:
简化建造者模式:
- “建造者模式好复杂,不用建造者模式,行不行?” 哈哈,当然可以的。如果不使用建造者模式,那么意味值客户端要自己构建和实例化Prodcut类,从零开始建造。看到区别了么?一种是给客户一个“手机”图纸,让客户自己去买配件,做“手机”;而建造者模式是把“手机”制造好后,给客户使用。
- “省略Builder和Director,直接使用工厂方法模式给客户生产手机OK么?” 这样当然可以啦,客户可以通过工厂方法直接拿到手机,工厂方法中负责手机零件和购买和组装。但这种方式的问题是什么呢?如果是生产一个手机模型,工厂方法应该是能够胜任的,因为这个产品足够简单。但要是生成真正的手机,工厂方法承担的职责就太重了,“建造者模式中”的Builder和Director可以把工厂方法解放出来,进一步Product实例化的灵活性。
3.举例
3.1 类图
客户端指定建造者Builder和建造流程Director,就可以拿到一个产成品啦。
3.2 代码实现
在示例代码中,我们通过两个不同的建造者,依据同一套流程,分别生成产品。
REPORT zbuilder_pattern.
**********************************************************************
* Product
**********************************************************************
CLASS lcl_product DEFINITION FINAL CREATE PUBLIC.
PUBLIC SECTION.
METHODS:
set_part_a
IMPORTING iv_part_a TYPE string,
set_part_b
IMPORTING iv_part_b TYPE string,
set_part_c
IMPORTING iv_part_c TYPE string,
display.
PRIVATE SECTION.
DATA mv_part_a TYPE string.
DATA mv_part_b TYPE string.
DATA mv_part_c TYPE string.
ENDCLASS.
CLASS lcl_product IMPLEMENTATION.
METHOD set_part_a.
mv_part_a = iv_part_a.
ENDMETHOD.
METHOD set_part_b.
mv_part_b = iv_part_b.
ENDMETHOD.
METHOD set_part_c.
mv_part_c = iv_part_c.
ENDMETHOD.
METHOD display.
WRITE: / 'This prodcut contains 3 part:'.
WRITE: / 'The frist part is:' && mv_part_a.
WRITE: / 'The second part is:' && mv_part_b.
WRITE: / 'The third part is:' && mv_part_c.
ENDMETHOD.
ENDCLASS.
**********************************************************************
* Builder
**********************************************************************
INTERFACE lif_builder.
METHODS:
build_part_a,
build_part_b,
build_part_c,
get_result
RETURNING
VALUE(ro_product) TYPE REF TO lcl_product.
ENDINTERFACE.
CLASS lcl_builder_1 DEFINITION FINAL CREATE PUBLIC.
PUBLIC SECTION.
METHODS constructor.
INTERFACES lif_builder.
PRIVATE SECTION.
DATA mo_product TYPE REF TO lcl_product.
ENDCLASS.
CLASS lcl_builder_1 IMPLEMENTATION.
METHOD constructor.
mo_product = NEW #( ).
ENDMETHOD.
METHOD lif_builder~build_part_a.
mo_product->set_part_a( 'Part A' ).
ENDMETHOD.
METHOD lif_builder~build_part_b.
mo_product->set_part_b( 'Part B' ).
ENDMETHOD.
METHOD lif_builder~build_part_c.
mo_product->set_part_c( 'Part C' ).
ENDMETHOD.
METHOD lif_builder~get_result.
ro_product = mo_product.
ENDMETHOD.
ENDCLASS.
**********************************************************************
CLASS lcl_builder_2 DEFINITION FINAL CREATE PUBLIC.
PUBLIC SECTION.
METHODS constructor.
INTERFACES lif_builder.
PRIVATE SECTION.
DATA mo_product TYPE REF TO lcl_product.
ENDCLASS.
CLASS lcl_builder_2 IMPLEMENTATION.
METHOD constructor.
mo_product = NEW #( ).
ENDMETHOD.
METHOD lif_builder~build_part_a.
mo_product->set_part_a( 'Part X' ).
ENDMETHOD.
METHOD lif_builder~build_part_b.
mo_product->set_part_b( 'Part Y' ).
ENDMETHOD.
METHOD lif_builder~build_part_c.
mo_product->set_part_c( 'Part Z' ).
ENDMETHOD.
METHOD lif_builder~get_result.
ro_product = mo_product.
ENDMETHOD.
ENDCLASS.
**********************************************************************
* Director
**********************************************************************
CLASS lcl_director DEFINITION FINAL CREATE PUBLIC.
PUBLIC SECTION.
METHODS construct
IMPORTING
io_builder TYPE REF TO lif_builder
RETURNING
VALUE(ro_product) TYPE REF TO lcl_product.
ENDCLASS.
CLASS lcl_director IMPLEMENTATION.
METHOD construct.
io_builder->build_part_a( ).
io_builder->build_part_b( ).
io_builder->build_part_c( ).
ro_product = io_builder->get_result( ).
ENDMETHOD.
ENDCLASS.
**********************************************************************
START-OF-SELECTION.
DATA(lo_director) = NEW lcl_director( ).
DATA(lo_builder_1) = NEW lcl_builder_1( ).
DATA(lo_builder_2) = NEW lcl_builder_2( ).
DATA(lo_prodcut_1) = lo_director->construct( lo_builder_1 ).
DATA(lo_prodcut_2) = lo_director->construct( lo_builder_2 ).
lo_prodcut_1->display( ).
lo_prodcut_2->display( ).
运行结果:
以上是对建造者模式的总结,欢迎分享、留言。😉
本博客专注于技术分享,干货满满,持续更新。
欢迎关注❤️、点赞👍、转发📣!