在将模式之前,先对一个OO设计原则掌握
对扩展开放和对修改关闭
无论如何,程序不能因为一些功能的修改就去该原来写的,这样只会越改越乱,因此,对修改屏蔽,和新增加的功能使用扩展的方式添加进去
装饰者模式正可以做到这一点。这里碰到的问题就是,软件应对变化的能力,装饰者模式提高了软件的弹性,增加了可维护性
到底是怎么做到的呢?
首先来看个实例,有个咖啡厅提供一个计价的软件,怎么才能描述各种咖啡饮料价格,
这里可以设计一个Berverge的父类,提供各个子类就行了
然而当饮料的各种配料也要计价进去时怎么办??
不可能为每个饮料和配料组成写个类 ----------疯了
当然你可以将所有的配料加入berverge中,返回他们的价格,并在cost()时加入要加的配料价格,这里也有个problem:对于将来加入的新的配料,需要修改源码就违反了先前说的
OO原则
那怎么办?
装饰者模式,就是在运行时动态的加入新的行为的一种设计模式。
首先,对于berverge类提供各种配料的封装
Class Berverge{
public double abstract cost();
}
Class Moka extends Berverge{
private Berverge berverge;
public Moka(Berverge berverge){
this.berverge = berverge;
}
public double cost(){
return 0.15 + berverge.cost();
}
}
装饰在那里??
在一杯摩卡咖啡时,只要提供一个Moka的Berverge对一个咖啡的封装就行了
如 new Moka(new Coffee()).cost();//这样就能得到一杯摩卡咖啡的价格了
装饰模式是如何做到这一点的??
继承,早就知道通过继承能够得到对象的行为的复用,但是,这里的继承是对类型的继承 , 为什么,因为Moka 和Coffee都来自于Berverge类,因此可以在Moka中
做到对行为的动态变化,Moka调用Coffee的行为,并在调用此行为的前后增加自己的行为
这里这个问题就解决了
可以通过提供各种配料的Berverge子类,当需要的什么饮料和不论多少配料时,只要不停的装饰就行了(多个装饰对象装饰一个组件)
new XX(new XX(new XX...))这样就能得到所有组合的价格
同有新的饮料或配料时,也没有问题,只要添加相应的类,使用时装饰进去就行了
(可见装饰模式对变化有很好的弹性)
那装饰模式有什么不足吗???
首先装饰模式,意味着一些不同就是一个小类,可能会造成类很多
然后 当你使用的类有特殊的行为时,装饰模式为出错,它只能处理Berverge中的普变行为(Normal)
最后 就是 装饰者的得到非常复杂(初始化,有很多的new),工厂模式和Builder模式也许能解决这个问题,我学到时再将
JDK中的装饰
最好的体现就是IO
FilterInputStream就是IO中所有装饰类的父类
你可以同继承它来实现自己的IO类,封装一些读取时的行为,比如大小写转换等,见例:
Class LowCaseInputStream extends FilterInputStream{
public LowCaseInputStream(InputStream in){
super(in);
}
public int read(){
int c = super.read();
return c==-1 ?-1:Character.toLowerCase((char)c);
}
public byte[] read(byte[]b , int start, int len){
byte[] b = super.read(b,start,len);
int length = b.length();
for(int i=0;i<length ; i++){
b[i] = (byte)Character.toLowerCase((char)b[i]);
}
}
}