定义
装饰模式是一种利用对象的关联关系来拓展对象功能的模式,并对外提供透明访问。由其名称中“装饰”两个字可知,该模式强调为对象添加职责,为了不违背单一职责原则,降低复杂度,所以提供装饰类对被装饰类加以修饰,这里称被装饰类为原始构件类,在每个装饰类中提供一个需要附加或添加的职责,所以一般需要一个抽象的装饰类。整个结构满足每个单独类都提供一个职责,通过装饰类对构件类进行包装来提供目标服务方法。
结构
由定义可知结构如下
结构中包含如下部分:
1、抽象构件类Component,声明目标服务方法
2、具体构件类Concrete_Component,提供原始功能
3、抽象装饰类Decorator,实现抽象构件类,并包含一个对抽象构件的引用,在实现方法中调用引用对象的实现
4、具体装饰类Concrete_Decorator,在重写的方法中添加职责,并调用原对象封装对象职责(这里说是原封装对象是因为可能进行了多层封装)
对比其他结构
拓展功能常使用继承方式,例如以animal作为抽象动物类,bird继承animal中的基本动物方法,并提供fly方法,fish继承animal中的基本动物方法,并提供swim方法,现在添加一个白鹭egret类,既需要实现fly方法,也需要实现swim方法,多继承的方式可能会造成使用方式受限(当然实际牵涉到动物类一般都是这种继承关系,此处只用来举例);
更常见的例子如对石块的操作可以包含两个步骤,雕刻(方式1、方式2、方式3。。。),上色(方式1、方式2、方式3。。。),如果使用继承的方式进行拓展,则可能存在一大堆的类,每个雕刻方式对应多个上色方式(看到这,其实最先想到的是之前的桥接模式,将雕刻和上色作为两个变化因素,进行分隔为两个继承体系,在抽象层建立关联关系,不过这里使用装饰模式,因为对于不同类型的石器材料有些可能只需要雕刻操作即可,即不需要提供上色步骤,装饰模式其实不光跟桥接模式接近,还有点像代理模式)。
由上面的继承结构可知,继承方式耦合性太强,扩展性不高,根据装饰模式定义,只需将carve方式作为原始构件类,上色操作作为装饰类提供附加职责即可。
在carve1、carve2中实现具体的雕刻操作,decorator用于代表需要额外添加的抽象上色操作。
参考代码
class t{
public static void main(String[] args){
stone c1=new carve1();
stone d1=new color1(c1);
stone d2=new color2(d1);
d2.show();
}
}
interface stone{//抽象构建类
void show();
}
class carve1 implements stone{//原始职责的构建类
public void show(){
System.out.println("carve1 action.");
}
}
class carve2 implements stone{//原始职责的构建类
public void show(){
System.out.println("carve2 action.");
}
}
class decorator implements stone{//抽象装饰类
private stone st;
public decorator(stone st){
this.st=st;
}
public void show(){
st.show();
}
}
class color1 extends decorator{//具体装饰类
public color1(stone st){
super(st);
}
public void show(){
append_operation();//添加职责
super.show();
}
public void append_operation(){
System.out.println("color1 action append.");
}
}
class color2 extends decorator{
public color2(stone st){
super(st);
}
public void show(){
append_operation();
super.show();
}
public void append_operation(){
System.out.println("color2 action append.");
}
}
总结
由装饰模式定义可知,该模式侧重于以透明方式对原始构件类,以关联关系而非继承的方式,添加额外的职责,当需要新添加一种职责时,只需要实现抽象装饰类即可。
这里有一种透明装饰模式和不透明装饰模式的差异:
上述定义操作,在满足抽象构件中声明的服务时,添加职责的方式对外界是透明的,即不可知的。如果在某种情形下,例如某位雕刻家走另类艺术,拿块石头不雕刻,喷上色就算完成了,即需要明确执行具体装饰类中添加的某项职责,此时定义具体装饰对象的引用变量类型不能为抽象构件类型stone,而必须是color1或者color2类型,即需要客户端做额外的执行职责,添加的功能对客户端不透明。