装饰者模式

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类也说不定,抽象类不能实例化,这样定义也许是为了更灵活考虑一点吧.

原文地址:https://www.cnblogs.com/lishuaiqi/p/11108416.html