原文地址: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方法的顺序画出来就比较容易理解了,说明如下: