- 定义:动态地将责任附加到对象上。想要扩展功能,装饰者提供有别于继承的另一种选择。
- 原则:对扩展开放,对修改关闭
当阅读代码时,发现在new一个对象时传递的参数也是new的一个对象,而参数对象的参数也是new了一个对象,而且这些对象直接或间接的继承了一个基类,那么就很有可能时装饰者设计模式,可以把装饰者模式理解为一种功能增强。
比如Java I/O就是典型的装饰者模式:
InputStream in = new MyTestInputStream(new BufferedInputStream(new FileInputStream("test.txt")));
老套路,举例说明,现在想做一个蛋糕,然后根据蛋糕的大小和所用的配料来算钱,所以要先设计一个蛋糕的基类:
public abstract class Cake{
String desc = "未知大小";
public String getDesc(){return desc;}//蛋糕的描述
public abstract int cost();//蛋糕的费用
}
再来设计一个配料的抽象类,一个蛋糕可以有多种配料,该类的作用主要用于最后描述蛋糕有那些配料组成:
public abstract class Mixture extends Cake{
public abstract String getDesc();//所有的配料都要重新实现这个方法
}
不明白它的作用?不着急,先继续往下看。
现在来实现蛋糕的具体类型,比如大蛋糕和小蛋糕:
public class BigCake extends Cake{
public BigCake(){desc = "我是一个大蛋糕";}//desc从Cake类继承过来
public int cost(){return 99;}
}
public class SmallCake extends Cake{
public SmallCake(){desc = "我是一个小蛋糕";}
public int cost(){return 49;}
}
上面的就是一个蛋糕的主体部分,蛋糕的基类看作是抽象的组件,实现类可以看作时具体的组件,接下来就来实现具体的装饰者类了:
public class Cream extends Mixture{//奶油
Cake cake;
public Cream(Cake cake){this.cake=cake;}
public Stirng getDesc(){
return cake.getDesc()+",Cream";//在蛋糕的描述中添加该配料
}
public int cost(){
return 15+cake.cost();//将15块钱的成本累加到蛋糕上
}
}
public class Chocolate extends Mixture{//巧克力
//与上面的基本类似,就省略了
//cost=10
}
public class Fruit extends Mixture{//水果
//同上
//cost=20
}
实现了三个配料类作为蛋糕的装饰器,接下来就看看怎么来用了。
现在女朋友要过生日了准备买个蛋糕,他喜欢巧克力蛋糕还要特别多的水果的那种,好办,定做一个大蛋糕,加上巧克力,然后加上双份的水果。
public class CakeTest{
public static void main(String args[]){
Cake myCake = new BigCake();//大蛋糕的底盘
myCake = new Chocolate(myCake);//加上巧克力配料
myCake = new Fruit(myCake);//加上水果
myCake = new Fruit(myCake);//再来一份水果
System.out.println(myCake.getDesc()+" 费用="+myCake.cost());
}
}
运行结果如下:
我是一个大蛋糕,Chocolate,Fruit,Fruit 费用=149
测试类中的装饰过程也可以写成一行,效果时一样的,这就可文章开头的Java I/O的代码有点类似了,当然啦,因为他们都使用了装饰者设计模式。有兴趣的朋友可以去看看Java I/O的源码。
参考书籍:《Head First设计模式》 作者:Eric Freeman&Elsabeth Freeman&Kathy Sierra&Bert Bates
菜鸟手书,欢迎指正!