装饰者模式
1.定义
动态的将责任附加到对象上,提供了比继承更有弹性的替代方案.
关键点: 装饰者和被装饰者必须有共同的超类.
2.代码实现
比如有一杯咖啡,咖啡有各种价钱,我想给咖啡增添各种调料,比如摩卡,豆浆,奶泡等等,相应的咖啡的价钱也会增加.
定义共同的超类Beverage类,Beverage类可以有子类,和一个抽象装饰类,抽象装饰类包含Beverage类,所以,抽象装饰类可以传入Beverage的子类来装饰咖啡等饮料
定义Beverage类
public abstract class Beverage { String description = "Unknow Beverage"; public String getDescription() { return description; } public abstract double cost(); }
Beverage抽象类有两个实现类Espresso(浓缩咖啡) 和 HouseBlend(混合咖啡)
public class Espresso extends Beverage { public Espresso() { description = "Espresso"; } @Override public double cost() { return 1.99; } }
public class HouseBlend extends Beverage { public HouseBlend() { description = "HouseBlend"; } @Override public double cost() { return 0.89; } }
以上两个类就是要被装饰的类
定义装饰者抽象类,这个抽象类的子类就是装饰类,可以装饰之前的浓缩咖啡和混合咖啡
public abstract class CondimentDecorator extends Beverage{ /** * 这里重写getDescription方法只是为了获取咖啡以及添加的调料的名称 */ public abstract String getDescription(); }
实现装饰者类,定义三种调料Moca(摩卡), Soy(豆浆),Whip(奶泡)
public class Moca extends CondimentDecorator{ Beverage beverage; public Moca(Beverage beverage) { this.beverage = beverage; } @Override public String getDescription() { return beverage.getDescription()+", Mocha"; } @Override public double cost() { return 0.20 + beverage.cost(); } }
public class Soy extends CondimentDecorator{ Beverage beverage; public Soy(Beverage beverage) { this.beverage = beverage; } @Override public String getDescription() { return beverage.getDescription()+", Soy"; } @Override public double cost() { return 0.10 + beverage.cost(); } }
public class Whip extends CondimentDecorator { Beverage beverage; public Whip(Beverage beverage) { this.beverage = beverage; } @Override public String getDescription() { return beverage.getDescription()+", Whip"; } @Override public double cost() { return 0.10 + beverage.cost(); } }
在这里我们可以看到,因为这三个类中都定义了Beverage变量,所以可以用构造函数接受传递过来的Beverage类,并且在cost和getDescription方法中调用Beverage类的方法来添加额外的数据,传递CondimentBeverage类也没有问题,因为CondimentBeverage类也是继承自Beverage类. 这就是为什么装饰者需要装饰类和被装饰类需要共同超类的原因.
接下来就可以测试了,定义测试类
public class StarbuzzCoffee { public static void main(String[] args) { Beverage beverage = new Espresso(); System.out.println(beverage.getDescription() + "/" + beverage.cost());//Espresso/1.99 Beverage beverage2 = new HouseBlend();//价格为0.89 beverage2 = new Soy(beverage2);//加上0.1 的豆浆 beverage2 = new Whip(beverage2);//在加上0.1 的奶排 beverage2 = new Moca(beverage2);//在加上0.2 的摩卡 System.out.println(beverage2.getDescription() + "/" + beverage2.cost());//HouseBlend, Soy, Whip, Mocha/1.29 } }
3.总结
装饰器模式的关键就是需要共同的超类,并且在装饰抽象类的子类中定义了超类变量,来装饰超类的.
java中的I/O类就是使用的装饰器模式,大部分类都是用来装饰InputStrem和OutputStrem类的,FilterInputStreamm是抽象装饰类,虽然FilterInputStream没有定义成abstract类型的,但是我们看下源码就知道它其实和装饰器模式一模一样.
源码如下:
public class FilterInputStream extends InputStream { /** * The input stream to be filtered. */ protected volatile InputStream in; /** * Creates a <code>FilterInputStream</code> * by assigning the argument <code>in</code> * to the field <code>this.in</code> so as * to remember it for later use. * * @param in the underlying input stream, or <code>null</code> if * this instance is to be created without an underlying stream. */ protected FilterInputStream(InputStream in) { this.in = in; } }
里面也包含了超类InputStream变量,并且构造函数给这个变量赋值,在以下方法中都是调用in.XXX方法来实现read,skip,close方法.
虽然没有搞懂为什么不定义成abstract类,但是构造函数是protected类型的,只有在子类中可以生成FilterInputStream类,或许别的地方需要实例化FilterInputStream类也说不定,抽象类不能实例化,这样定义也许是为了更灵活考虑一点吧.