原文地址:http://tech.sina.com.cn/s/2009-08-07/10501017673.shtml
概述
OO编程23种设计模式之一,英文叫Decorator Pattern,又叫装饰者模式。装饰模式是在不必改变原类文件和使用继承的情况下,动态的扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。
装饰模式的特点
(1) 装饰对象和真实对象有相同的接口。这样客户端对象就可以和真实对象相同的方式和装饰对象交互。
(2) 装饰对象包含一个真实对象的引用(reference)
(3) 装饰对象接受所有来自客户端的请求。它把这些请求转发给真实的对象。
(4) 装饰对象可以在转发这些请求以前或以后增加一些附加功能。这样就确保了在运行时,不用修改给定对象的结构就可以在外部增加附加的功能。在面向对象的设计中,通常是通过继承来实现对给定类的功能扩展。
装饰者与适配者模式的区别
1.关于新职责:适配器也可以在转换时增加新的职责,但主要目的不在此。装饰者模式主要是给被装饰者增加新职责的。
2.关于原接口:适配器模式是用新接口来调用原接口,原接口对新系统是不可见或者说不可用的。装饰者模式原封不动的使用原接口,系统对装饰的对象也通过原接口来完成使用。(增加新接口的装饰者模式可以认为是其变种--“半透明”装饰者)
3.关于其包裹的对象:适配器是知道被适配者的详细情况的(就是那个类或那个接口)。装饰者只知道其接口是什么,至于其具体类型(是基类还是其他派生类)只有在运行期间才知道。[1]
http://baike.baidu.com/view/2787758.htm
首先,按照惯例,上例子程序的类图
测试程序如下:
测试程序如下:
REPORT zgary_t009.
INCLUDE zgary_t009_class_define.
*Reference data for drink definition
DATA: dr_ref TYPE REF TO drink.
*Temp reference for decorator
DATA:tdr TYPE REF TO drink.
START-OF-SELECTION.
*-------------------start decorate---------------*
"Narrowing cast
"Create darkroast object
CREATE OBJECT tdr TYPE darkroast.
"Make dr_ref point to the object darkroast
"And this is the need to be decorated material
dr_ref = tdr.
" Use mocha to decorate object darkroast
CREATE OBJECT tdr TYPE mocha
EXPORTING
dr = dr_ref. "This dr_ref is darkroast
dr_ref = tdr.
" Use soy to decorate object mocha&darkroast
CREATE OBJECT tdr TYPE soy
EXPORTING
dr = dr_ref. "This dr_ref is mocha
dr_ref = tdr.
" Use whip to decorate object soy&mocha&darkroast
CREATE OBJECT tdr TYPE whip
EXPORTING
dr = dr_ref. "This dr_ref is soy
dr_ref = tdr.
*-------------------end decorate---------------*
* Define data which used to display data
DATA: ls TYPE string,lf TYPE f.
" Get description
ls = dr_ref->getdesc( ).
" Get cost
lf = dr_ref->cost( ).
"Display result
WRITE: / ls, ':$',lf DECIMALS 2 EXPONENT 0.
*&---------------------------------------------------------------------*
*& Include ZGARY_T009_CLASS_DEFINE
*&---------------------------------------------------------------------*
* For the Decorator pattern, normally using an abstract super class
* And the Decorator class inherite from the super class also as an
* abstract class
* Super abstract class with drink
CLASS drink DEFINITION ABSTRACT.
PUBLIC SECTION.
DATA: desc TYPE string.
METHODS:
"Get the drink's description
getdesc RETURNING value(de) TYPE string,
" Because the cost must be calculate from every concrete material
" It should be an abstract method
cost ABSTRACT RETURNING value(co) TYPE f.
ENDCLASS. "drink DEFINITION
*Implement the drink class
CLASS drink IMPLEMENTATION.
METHOD getdesc.
"Return the description
de = desc.
ENDMETHOD. "getdesc
ENDCLASS. "drink IMPLEMENTATION
*定义concrete component,在我们的例子中,它是饮料类的一个子类darkroast
*An concrete class for drink, as one need to be decorated
CLASS darkroast DEFINITION INHERITING FROM drink.
PUBLIC SECTION.
METHODS:
" initialization
constructor,
"The subclass should implement abstract method from super
cost REDEFINITION.
ENDCLASS. "drink IMPLEMENTATION
*Implement darkroast
CLASS darkroast IMPLEMENTATION.
METHOD constructor.
CALL METHOD super->constructor.
" Give a new description
desc = 'Darkroast'.
ENDMETHOD. "constructor
METHOD cost.
" Get the raw material cost
co = '1.99'.
ENDMETHOD. "cost
ENDCLASS. "darkroast IMPLEMENTATION
*定义装饰者抽象类,注意,他只不过继承了drink类,并没有作什么,我们需要的只不过是一个接口,一个装饰者和被装饰者的交互接口。
*Decorator definition, which will decorate the raw material
*The decorator should be as abstract class
*It is just for supply an interface, it won't implement
*any method of super class
*Or you could define new method here so that the subclass
*of decorator should have new method in it
CLASS decorator DEFINITION ABSTRACT
INHERITING FROM drink.
ENDCLASS. "darkroast IMPLEMENTATION
*----------------------------------------------------------------------*
* CLASS decorator IMPLEMENTATION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS decorator IMPLEMENTATION.
ENDCLASS. "decorator IMPLEMENTATION
*定义具体的装饰者
*Define the concrete decorator which will used to decorate
* the concrete drink object, for exp: darkroast
CLASS mocha DEFINITION INHERITING FROM decorator.
PUBLIC SECTION.
" Define the interface which will point to super class drink
DATA:
drink TYPE REF TO drink.
METHODS:
" Ininitialization
constructor
IMPORTING dr TYPE REF TO drink,
" Redifine the getdesc method so that we can get the right name
" of the decorated drink
getdesc REDEFINITION,
" Redifine the cost method so that we can get the right price
" of the decorated drink
cost REDEFINITION.
ENDCLASS. "decorator IMPLEMENTATION
*----------------------------------------------------------------------*
* CLASS mocha IMPLEMENTATION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS mocha IMPLEMENTATION.
METHOD constructor.
CALL METHOD super->constructor.
" Make drink instance variant point to decorator
" For example, if darkroast decorated with mocha
" the reference drink shoul be pointed to darkroast
drink = dr.
ENDMETHOD. "constructor
METHOD getdesc.
" This method will show how many decorate material we used
DATA: ls_mocha TYPE string.
ls_mocha = drink->getdesc( ).
CONCATENATE ls_mocha ',Mocha' INTO de.
ENDMETHOD. "getdesc
METHOD cost.
" Calculate the total price of the new drink which be decorated
" by the decorator
DATA: lf_mocha TYPE f.
lf_mocha = drink->cost( ).
co = lf_mocha + '0.20'.
ENDMETHOD. "cost
ENDCLASS. "mocha IMPLEMENTATION
*定义其他的装饰者,和上面的差不多
*The below part is mostly the same as mocha, because all of them
*are decorators for the drink raw material
CLASS soy DEFINITION INHERITING FROM decorator.
PUBLIC SECTION.
DATA: drink TYPE REF TO drink.
METHODS:
constructor
IMPORTING dr TYPE REF TO drink,
getdesc REDEFINITION,
cost REDEFINITION.
ENDCLASS. "mocha IMPLEMENTATION
*----------------------------------------------------------------------*
* CLASS soy IMPLEMENTATION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS soy IMPLEMENTATION.
METHOD constructor.
CALL METHOD super->constructor.
drink = dr.
ENDMETHOD. "constructor
METHOD getdesc.
DATA: lssoy TYPE string.
lssoy = drink->getdesc( ).
CONCATENATE lssoy ',Soy' INTO de.
ENDMETHOD. "getdesc
METHOD cost.
DATA: lfsoy TYPE f.
lfsoy = drink->cost( ).
co = lfsoy + '0.40'.
ENDMETHOD. "cost
ENDCLASS. "soy IMPLEMENTATION
*----------------------------------------------------------------------*
* CLASS whip DEFINITION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS whip DEFINITION INHERITING FROM decorator.
PUBLIC SECTION.
DATA: drink TYPE REF TO drink.
METHODS:
constructor
IMPORTING dr TYPE REF TO drink,
getdesc REDEFINITION,
cost REDEFINITION.
ENDCLASS. "whip DEFINITION
*----------------------------------------------------------------------*
* CLASS whip IMPLEMENTATION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS whip IMPLEMENTATION.
METHOD constructor.
CALL METHOD super->constructor.
drink = dr.
ENDMETHOD. "constructor
METHOD getdesc.
DATA: lswhip TYPE string.
lswhip = drink->getdesc( ).
CONCATENATE lswhip ',Whip' INTO de.
ENDMETHOD. "getdesc
METHOD cost.
DATA: lfwhip TYPE f.
lfwhip = drink->cost( ).
co = lfwhip + '0.60'.
ENDMETHOD. "cost
ENDCLASS. "whip IMPLEMENTATION
运行结果:
这个程序比较难理解,有点像我们平时写的递归,下面我把getdesc方法的顺序画出来就比较容易理解了,说明如下: