设计模式(3)装饰者模式

我们到咖啡店喝咖啡的时候,往往会根据各自的口味去选择咖啡和各种配料,比如咖啡可以选择综合、焙、低咖啡因、浓缩,配料可以选搭牛奶、摩卡、豆浆、奶泡。这个情境下就可以使用装饰者模式,用配料对咖啡进行装饰,组合成不同的咖啡。 

装饰者模式——动态的将职责附加到对象上。想要扩展功能,装饰者模式是有别于继承的另一种选择。

装饰者和被装饰者对象有相同的超类,可以用一个或多个装饰者装饰一个对象,装饰者可以在被装饰者的行为之前或之后,加上自己的行为,从而达到特定的目的。

比如咖啡和配料都继承于一个超类Beverage,首先最底层是一个咖啡对象,然后一层层的用配料去装饰咖啡对象,最终得到了一个被装饰完成的对象。

下面看下代码

装饰者和被装饰在的超类

public abstract class Beverage {

    /**
     * 大小
     */
    private SizeEnum size;
    /**
     * 描述
     *
     * @return 描述
     */
    public abstract String getDescription();

    /**
     * 花费
     *
     * @return 花费
     */
    public abstract double cost();

    public SizeEnum getSize() {
        return size;
    }

    public void setSize(SizeEnum size) {
        this.size = size;
    }
}

装饰者的父类

public class CondimentDecorator extends Beverage{
    @Override
    public String getDescription() {
        return null;
    }

    @Override
    public double cost() {
        return 0;
    }
}

杯子大小的枚举

public enum SizeEnum {

    /**
     * 小杯
     */
    TALL(1, "小杯"),
    /**
     * 中杯
     */
    GRANDE(2, "中杯"),
    /**
     * 大杯
     */
    VENTI(3, "大杯");

    SizeEnum(int value, String caption) {
        this.value = value;
        this.caption = caption;
    }

    /**
     * 大小
     */
    private int value;
    /**
     * 描述
     */
    private String caption;

    public int getValue() {
        return value;
    }

    public void setValue(int value) {
        this.value = value;
    }

    public String getCaption() {
        return caption;
    }

    public void setCaption(String caption) {
        this.caption = caption;
    }
}

几个继承了超类的咖啡类

public class DarkRoast extends Beverage {

    public DarkRoast(SizeEnum sizeEnum) {
        super.setSize(sizeEnum);
    }

    @Override
    public String getDescription() {
        return "DarkRoast";
    }

    @Override
    public double cost() {
        return 0.99;
    }
}
public class Decaf extends Beverage {

    public Decaf(SizeEnum sizeEnum) {
        super.setSize(sizeEnum);
    }

    @Override
    public String getDescription() {
        return "Decaf";
    }

    @Override
    public double cost() {
        return 1.05;
    }
}
Decof
public class Espresso extends Beverage {

    public Espresso(SizeEnum sizeEnum) {
        super.setSize(sizeEnum);
    }

    @Override
    public String getDescription() {
        return "Espresso";
    }

    @Override
    public double cost() {
        return 1.99;
    }
}
Espresso
public class HouseBland extends Beverage {

    public HouseBland(SizeEnum sizeEnum) {
        super.setSize(sizeEnum);
    }

    @Override
    public String getDescription() {
        return "HouseBland";
    }

    @Override
    public double cost() {
        return 0.89;
    }
}
HouseBland

装饰类

public class Milk extends CondimentDecorator {

    private Beverage beverage;

    public Milk(Beverage beverage) {
        this.beverage = beverage;
    }

    @Override
    public String getDescription() {
        return "Milk, " + beverage.getDescription();
    }

    @Override
    public double cost() {
        return beverage.cost() + 0.10;
    }

    @Override
    public SizeEnum getSize() {
        return beverage.getSize();
    }
}
public class Mocha extends CondimentDecorator {

    private Beverage beverage;

    public Mocha(Beverage beverage) {
        this.beverage = beverage;
    }

    @Override
    public String getDescription() {
        return "Mocha, " + beverage.getDescription();
    }

    @Override
    public double cost() {
        return beverage.cost() + 0.20;
    }

    @Override
    public SizeEnum getSize() {
        return beverage.getSize();
    }
}
Mocha
public class Soy extends CondimentDecorator {

    private Beverage beverage;

    public Soy(Beverage beverage) {
        this.beverage = beverage;
    }

    @Override
    public String getDescription() {
        return "Soy, " + beverage.getDescription();
    }

    @Override
    public double cost() {
        switch (this.getSize()) {
            case TALL:
                return beverage.cost() + 0.10;
            case VENTI:
                return beverage.cost() + 0.15;
            case GRANDE:
                return beverage.cost() + 0.20;
            default:
                return beverage.cost() + 0.10;
        }
    }

    @Override
    public SizeEnum getSize() {
        return beverage.getSize();
    }
}
Soy
public class Whip extends CondimentDecorator {

    private Beverage beverage;

    public Whip(Beverage beverage) {
        this.beverage = beverage;
    }

    @Override
    public String getDescription() {
        return "Whip, " + beverage.getDescription();
    }

    @Override
    public double cost() {
        return beverage.cost() + 0.10;
    }

    @Override
    public SizeEnum getSize() {
        return beverage.getSize();
    }
}
Whip

 测试

public static void main(String[] args) {
        Beverage beverage1 = new Espresso(SizeEnum.GRANDE);
        System.out.println(beverage1.getSize().getCaption() + " " + beverage1.getDescription() + "  cost: " + beverage1.cost());
        Beverage beverage2 = new DarkRoast(SizeEnum.VENTI);
        beverage2 = new Mocha(beverage2);
        beverage2 = new Mocha(beverage2);
        beverage2 = new Milk(beverage2);
        System.out.println(beverage2.getSize().getCaption() + " " + beverage2.getDescription() + "  cost: " + beverage2.cost());
    }

输出

装饰者模式的运用有很多,例如Java I/O 中 BufferedInputStream, LineNumberInputStream扩展自FileInputStream,而FileInputStream是一个抽象的装饰类。

装饰者模式给我们带来了一种新的视角,除了使用继承,装饰者模式也可以对行为进行扩展。可以用无数的装饰者包装一个组件,但是装饰者模式会导致设计中出现许多的小对象,如果过渡使用的话,会让程序变得异常复杂。

原文地址:https://www.cnblogs.com/oeleven/p/10415906.html