装饰模式,正如字面意思所示,其主要的特点是模仿装饰的行为,实际上就是建造一种可以由装饰者对被装饰者进行装饰的架构。
装饰者每次对被装饰者进行装饰,都是基于上次装饰的结果进行累加。
假使被装饰者是一个没有化妆的女孩儿,装饰者可以先对女孩的头发进行装饰,装饰结果就是女孩拥有了一个时的发型,尔后,由另外一个装饰者对女孩子的眼睛进行装饰,于是女孩拥有了一双更加楚楚动人的大眼睛,这就是装饰者与被装饰者的关系和其之间互相作用的结果。
实际应用当中,装饰者模式的用途很广泛,比如计算一份饮料的成本,水是所有饮料都需要有的基础材料,有其相对固定的价格,于是水可以被当作被装饰者,而糖,奶,可可等调料由于饮料品种不一,配料不一,其价格也不定,则可以做为装饰者对水进行装饰,比如,我需要一杯糖水,那么用糖装饰水,则可以算出糖水的价格,实际上就是用糖的价格加上水的价格,比如我需要一杯可可水,那么需要奶,糖,以及可可对谁进行装饰,先将可可装饰水,然后用糖装饰可可水,再用奶装饰甜的可可水,这样一杯香滑甜润的可可奶饮料就生产出来了,其成本依然是水+可可+奶+糖的成本之和,这就是一个典型应用,我们可以根据需要运用现有的装饰者达到我们的定制化需求,具体代码就是这样:
特征接口 水=new 糖(水);//用糖类装饰水类
水=new 奶(水);//用奶类装饰水类
水=new 可可(水);//用可可装饰水类
水.计算价格
为了达到以上的行为方式,装饰者模式分成几个角色:
装饰者类,被装饰者类,特征接口
重点说一下这个特征接口,装饰者和被装饰者,都需要继承于此,由于装饰者需要对被装饰者进行运行时动态调用,所以这个特征接口,只是作为类型通用化的一个手段。‘
拿上面的例子来说
特征接口应该具备至少两个方法:返回价格 、返回名称
interface BaseClass
{
int GetCost();
string GetName();
}
水类(相当于被装饰者类)以及装饰者(如奶,糖,可可等类)的超类继承于这个BaseClass
class Water:BaseClass//水充当的角色是被装饰者
{
string GetName()
{
return "水";
}
int GetCost()
{
return 1;//水的价格是1块钱
}
}
abstract class 装饰者:BaseClass
{
abstract int GetCost();//由于装饰者在这里的位置是超类,所有的装饰者都需要实现自身的这个方法
abstract int GetName();//由于装饰者在这里的位置是超类,所有的装饰者都需要实现自身的这个方法
BaseClass 被装饰者;
装饰者(BaseClass 被装饰者)
{
this.被装饰者=被装饰者;
}
}
class 奶:装饰者
{
奶(BaseClass 被装饰者):base(被装饰者)//将被装饰者通过基类的方法进行处理
{}
int GetCost()
{
被装饰者.GetCost()+1.5;//返回价格,注意,此价格是累加价格,调用被装饰的类的GetCost方法
}
string GetName()
{
return "奶";//名称是奶
}
}
class 可可:装饰者
{
可可()......依此类推
}
调用代码:
BaseClass 水=new 糖(水);//用糖类装饰水类,将水类的实例赋值给糖.被装饰者
水=new 奶(水);//用奶类装饰水类,将被糖装饰好的糖水类的实例赋值给奶.被装饰者
水=new 可可(水);//用可可装饰水类
水.GetCost()//这里实际上是调用了水.GetCost()->糖.GetCost()->奶.GetCost()->可可.GetCost()方法,我们利用如上代码,实际上是建立了一个单向链表而已,调用的时候也是按照链表顺序调用方法。
总结:实际上,装饰模式,就是将类,通过链表的形式链接在一起,然后从链表头部(最后一个装饰者类)经过多个装饰者,最后到达被装饰者类,依次嵌套调用这些类的GetCost方法得到价格的累加。
好了,这个模式大概的机制已经介绍完了,如果对您的学习有所帮助,是我最大的荣誉。