转载请注明出处:http://blog.csdn.net/droyon/article/details/8630106
装饰者模式:顾名思义将对象装饰的更加漂亮,只是更漂亮,他还是他,没有改变类型。
官方定义:动态的将责任附加到对象上。若要扩展功能,装饰着提供了比继承更有弹性的替代方案。
案例情景:
煎饼果子(pancake),包含一个鸡蛋、一个脆饼。我们可以选择加辣椒(pepper),可以选择加香肠(Sausage),可以选择多加鸡蛋(Eggs)。(上地软件园路上的煎饼果子,你懂的!)
我们要实现对每一个煎饼果子进行描述。例如:”煎饼果子、不要辣椒“
我们如果为每一个煎饼果子都构建一个类,比如 PancakeWithPepper、PancakeWithSausage,那么我们就制造了一个维护的噩梦,比如如果多加一个蛋,可以写PancakeWithONeEggs、那么多加俩蛋那、仨蛋那?PancakeWithThreeEggs?
装饰着模式可以很好的解决这类问题。
源代码下载
Pancake.java//煎饼果子
public class Pancake {
public Pancake() {
};
public String toString(){
return "[煎饼:一个鸡蛋,一个脆饼--4元一个]";
}
public int cost(){
return 4;
}
}
public class DecoratorEggs extends Pancake{
Pancake mPancake;
private int mEggsCount;
public DecoratorEggs(Pancake p,int count){
mPancake = p;
mEggsCount = count;
}
@Override
public String toString() {
return mPancake.toString() + "[+"+mEggsCount+"个鸡蛋--1元1个]";
}
@Override
public int cost() {
return mPancake.cost()+1*mEggsCount;
}
}
public class DecoratorPepper extends Pancake{
Pancake mPancake;
public DecoratorPepper(Pancake p){
mPancake = p;
}
@Override
public String toString() {
return mPancake.toString()+"[放辣椒]";
}
@Override
public int cost() {
return mPancake.cost();
}
}
public class DecoratorPepper extends Pancake{
Pancake mPancake;
public DecoratorPepper(Pancake p){
mPancake = p;
}
@Override
public String toString() {
return mPancake.toString()+"[放辣椒]";
}
@Override
public int cost() {
return mPancake.cost();
}
}
DecoratorTest.java//测试类
public class DecoratorTest {
public static void main(String args[]){
Pancake pancake = new Pancake();//一个普通煎饼
System.out.println(pancake+"价格:"+pancake.cost());
Pancake decoratorEggs = new DecoratorEggs(pancake, 2);//多加两个鸡蛋,用鸡蛋装饰煎饼
System.out.println(decoratorEggs+"价格:"+decoratorEggs.cost());
DecoratorPepper decoratorEggsAndPepper = new DecoratorPepper(decoratorEggs);//用两个鸡蛋装饰之后哦再用辣椒装饰它
System.out.println(decoratorEggsAndPepper+"价格:"+decoratorEggsAndPepper.cost());
Pancake pancakeWithEggsWithPepperWithSausage = new DecoratorSausage(decoratorEggsAndPepper);//继续装饰,用香肠装饰
System.out.println(pancakeWithEggsWithPepperWithSausage+"价格:"+pancakeWithEggsWithPepperWithSausage.cost());
DecoratorSausage decoratorSausage = new DecoratorSausage(new DecoratorEggs(new DecoratorPepper(new Pancake()), 1));//另外一个煎饼
decoratorSausage.setSausage(2);
System.out.println(decoratorSausage+"价格:"+decoratorSausage.cost());
}
}
[煎饼:一个鸡蛋,一个脆饼--4元一个]价格:4
[煎饼:一个鸡蛋,一个脆饼--4元一个][+2个鸡蛋--1元1个]价格:6
[煎饼:一个鸡蛋,一个脆饼--4元一个][+2个鸡蛋--1元1个][放辣椒]价格:6
[煎饼:一个鸡蛋,一个脆饼--4元一个][+2个鸡蛋--1元1个][放辣椒][加0根香肠--2元一根]价格:6
[煎饼:一个鸡蛋,一个脆饼--4元一个][放辣椒][+1个鸡蛋--1元1个][加2根香肠--2元一根]价格:9
总结:
继承可以扩展类的功能,但不见得是最好的方案。继承可以从父类那里得到定义好的属性和方法,但继承在实现起来不具备弹性。继承的行为是在编译时就决定好的,而且所有的子类都继承得到相同的行为。组合可以扩展对象的行为,在运行时动态的进行扩展。利用组合维护代码,通过动态的改变组合对象,可以实现不需要改变代码添加新功能的行为。
开放关闭原则:类应该对扩展开放,对修改关闭。---设计原则
在不需要改变代码的情况下,扩展类的行为。比如观察者模式,通过加入新的观察者,不需要修改主题的代码,我们可以在任何时候扩展类的行为。
装饰者对象和被装饰的对象拥有相同的超类型,也就是说,装饰之后,被装饰对象的类型不能变。这样在任何时候就可以通过新的装饰者装饰它。
在java语言中,我们看到的io操作,也就是流,他们也是装饰者对象的例子。InputStream可以读取字节,然后显示,BufferedInputStream包装了InputStream,将InputStream读取的内容放在缓冲区中,在读取结束后,一起显示。