1. 目的
不改动功能类的基础上,动态地给一个对象添加一些额外的职责。
2. 解析
类比:
- 装饰模式可以类比于现实世界的穿衣打扮过程。你的衣柜里有各种各样的衣服,在出门时,你可以选择当日的搭配,可以选择牛仔裤配格子衫,可以大体恤配短裤拖鞋。每一件衣服,可以可以类比成面向对象世界中的一个装饰类。
- 装饰类间相互独立,可以相互组合,合作完成一种功能搭配。
功能解析:
- 就增加功能来说,装饰模式比生成子类更灵活
- 把类中装饰的功能从类中搬出,这样可以简化原有的类
- 有效区分类的核心功能和装饰功能
- 使用时,应注意装饰类的调用顺序。当然,最理想的情况下,各个装饰类之间应当是相互独立的
- 调用方,不需要知道装饰类的存在
核心技术点:
- Decorator类和功能类之间形成“链状结构”,调用“本层”装饰类前,先调用“上层”装饰类/功能类。
结合应用
- 可以与工厂模式结合使用,工厂直接返回装饰后的实例对象。
代理模式体现的设计原则有:
- 单一职责原则 - 专业的类做专业的事
- 开放封闭原则 - 稳定的核心功能;但在不同的场景下,可以有多种不同的代理类
- 依赖倒置原则 - client在使用时,其实依赖的是接口,面向接口的编程
3. 类图
实现装饰模式可以有多种方法,本篇中给出了两种实现方式。
- 使用抽象类
- 使用接口
3.1 通过继承实现
创建抽象类decorator, 抽象类直接提供形成链状结构的set_component方法,然后继承抽象decorator类来实现不同的装饰类。
3.3 通过接口实现
装饰类和功能类,实现相同的接口。在实例化装饰类时,用mo_component存储功能类对象,实现链状结构。
3.3 调用时序图
无论通过哪种方式实现,达到的效果是相同的。Client调用功能时,装饰类并不会改变已有的接口结构,而仅仅是在原有功能上,附加了装饰功能。
4. 代码实现
4.1 通过继承实现
*&---------------------------------------------------------------------*
*& Report zdecorator_pattern
*&---------------------------------------------------------------------*
*&
*&---------------------------------------------------------------------*
REPORT zdecorator_pattern.
* here the component could be an interface object
CLASS lcl_component DEFINITION.
PUBLIC SECTION.
METHODS operation.
ENDCLASS.
CLASS lcl_component IMPLEMENTATION.
METHOD operation.
WRITE 'Specific operation from component.'.
ENDMETHOD.
ENDCLASS.
* Use decorator to extend the behavior of component
CLASS lcl_decorator DEFINITION
INHERITING FROM lcl_component.
PUBLIC SECTION.
METHODS set_component
IMPORTING
io_component TYPE REF TO lcl_component.
METHODS operation REDEFINITION.
PROTECTED SECTION.
DATA mo_component TYPE REF TO lcl_component.
ENDCLASS.
CLASS lcl_decorator IMPLEMENTATION.
METHOD set_component.
mo_component = io_component.
ENDMETHOD.
METHOD operation.
IF mo_component IS BOUND.
mo_component->operation( ).
ENDIF.
ENDMETHOD.
ENDCLASS.
* Specific decorator class to add specific behavior
CLASS lcl_decorator_a DEFINITION
INHERITING FROM lcl_decorator.
PUBLIC SECTION.
METHODS operation REDEFINITION.
PRIVATE SECTION.
DATA mv_state TYPE string.
ENDCLASS.
CLASS lcl_decorator_a IMPLEMENTATION.
METHOD operation.
super->operation( ).
mv_state = 'Some states were described'.
WRITE / 'Operation in decorator A'.
ENDMETHOD.
ENDCLASS.
* Specific decorator class to add specific behavior
CLASS lcl_decorator_b DEFINITION
INHERITING FROM lcl_decorator.
PUBLIC SECTION.
METHODS operation REDEFINITION.
PRIVATE SECTION.
METHODS added_behavior.
ENDCLASS.
CLASS lcl_decorator_b IMPLEMENTATION.
METHOD operation.
super->operation( ).
added_behavior( ).
WRITE / 'Operation in decorator B'.
ENDMETHOD.
METHOD added_behavior.
WRITE / 'Some added behavior was done in decorator B'.
ENDMETHOD.
ENDCLASS.
START-OF-SELECTION.
DATA: lo_component TYPE REF TO lcl_component,
lo_decorator_a TYPE REF TO lcl_decorator_a,
lo_decorator_b TYPE REF TO lcl_decorator_b.
" component and specific decorator is prepared
lo_component = NEW #( ).
lo_decorator_a = NEW #( ).
lo_decorator_b = NEW #( ).
" behavior of operation is extended by specific decorator
lo_decorator_a->set_component( lo_component ).
lo_decorator_b->set_component( lo_decorator_a ).
lo_decorator_b->operation( ).
4.2 通过接口实现
*&---------------------------------------------------------------------*
*& Report zdecorator_pattern
*&---------------------------------------------------------------------*
*&
*&---------------------------------------------------------------------*
REPORT zdecorator_pattern2.
* here the component is an dedicated interface
INTERFACE lif_component.
METHODS operation.
ENDINTERFACE.
* Target class implements he behavior of component interface
CLASS lcl_target DEFINITION.
PUBLIC SECTION.
INTERFACES: lif_component.
ENDCLASS.
CLASS lcl_target IMPLEMENTATION.
METHOD lif_component~operation.
WRITE / 'Operation in target'.
ENDMETHOD.
ENDCLASS.
* Specific decorator class a to add specific behavior
CLASS lcl_decorator_a DEFINITION.
PUBLIC SECTION.
METHODS constructor
IMPORTING
io_component TYPE REF TO lif_component.
INTERFACES: lif_component.
PRIVATE SECTION.
METHODS added_behavior.
DATA mo_component TYPE REF TO lif_component.
ENDCLASS.
CLASS lcl_decorator_a IMPLEMENTATION.
METHOD constructor.
mo_component = io_component.
ENDMETHOD.
METHOD lif_component~operation.
IF mo_component IS BOUND.
mo_component->operation( ).
added_behavior( ).
ENDIF.
ENDMETHOD.
METHOD added_behavior.
WRITE / 'Operation in decorator a'.
ENDMETHOD.
ENDCLASS.
* Specific decorator class b to add specific behavior
CLASS lcl_decorator_b DEFINITION.
PUBLIC SECTION.
METHODS constructor
IMPORTING
io_component TYPE REF TO lif_component.
INTERFACES: lif_component.
PRIVATE SECTION.
METHODS added_behavior.
DATA mo_component TYPE REF TO lif_component.
ENDCLASS.
CLASS lcl_decorator_b IMPLEMENTATION.
METHOD constructor.
mo_component = io_component.
ENDMETHOD.
METHOD lif_component~operation.
IF mo_component IS BOUND.
mo_component->operation( ).
added_behavior( ).
ENDIF.
ENDMETHOD.
METHOD added_behavior.
WRITE / 'Operation in decorator b'.
ENDMETHOD.
ENDCLASS.
START-OF-SELECTION.
DATA lo_component TYPE REF TO lif_component.
DATA lo_target TYPE REF TO lcl_target.
DATA lo_decorator_a TYPE REF TO lcl_decorator_a.
DATA lo_decorator_b TYPE REF TO lcl_decorator_b.
" prepare service via decorator
lo_target = NEW lcl_target( ).
lo_decorator_a = NEW lcl_decorator_a( lo_target ).
lo_decorator_b = NEW lcl_decorator_b( lo_decorator_a ).
" return service to client
lo_component = lo_decorator_b.
" Client uses service without knowing decorating details
lo_component->operation( ).
运行结果如下:
本博客专注于技术分享,干货满满,持续更新。
欢迎关注❤️、点赞👍、转发📣!