装饰者模式

2017-07-09  本文已影响0人  李小神不偷懒

业务场景:

火锅店有3种火锅底锅:鸳鸯锅,香辣锅,菌菇锅;有4种可加的菜:生菜,豆腐,羊肉,牛肉。如下图所示。顾客可以店一个底锅,配任任意菜(数量和种类都任意),那么顾客可能点的火锅种类就有点多了:鸳鸯锅加生菜加豆腐加羊肉,香辣锅加生菜加羊肉加牛肉,菌菇锅加3份羊肉加5份牛肉(豪),鸳鸯锅加1份生菜(生菜我都不想点)......在我们的程序中不可能穷举出所有的组合而事先实现所有的种类,我们只有让顾客在选择菜品时不断地动态地生成新的种类来满足顾客的需求。

动态生成新的种类,可以在之前已有的菜品的基础上增加生成新的菜品。也就是往已有的菜品中加菜,进行装饰或者包裹。如下图所示,按照用户点菜的顺序依次包裹形成最终的菜品。 这种采用层层包裹层层点缀生成新对象的方式就叫做装饰者模式。


实现

使用装饰者模式的首要要求就是装饰者和被装饰者必须具有相同的超类型。如下图所示,生菜、豆腐等装饰者都继承自HotPot类,这种继承结构总是让人感觉不舒服,因为毕竟火锅中加的菜一般我们不称之为火锅。但是,这种模式状态下请忽略这种字面的纠结,我们使用继承只是为了有正确的类型而不是继承它的行为。因为有了正确的类型,我们可以在对被装饰者进行装饰时,可以调用相同的api并对装饰者的进行行为的扩展。

public abstract class HotSpot {

    String description = "不知道什么火锅";

    public String getDescription() {
        return description;
    }

    public abstract double cost();
}

public class TwoFlavorHotPot extends HotSpot {

    public TwoFlavorHotPot() {
        description = "鸳鸯锅";
    }

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

public class SpicyHotPot extends HotSpot{

    public SpicyHotPot() {
        description = "香辣锅";
    }

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

public class MushroomHotSpot extends HotSpot{

    public MushroomHotSpot() {
        description = "菌菇锅";
    }

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

public abstract class CondimentDecorator extends HotSpot{
    public abstract String getDescription();
}

public class Lettuce extends CondimentDecorator {

    HotSpot hotSpot ;
    public Lettuce(HotSpot hotSpot) {
        this.hotSpot = hotSpot;
    }

    @Override
    public String getDescription() {
        return hotSpot.getDescription() + "加一份生菜";
    }

    @Override
    public double cost() {
        return hotSpot.cost() + 10;
    }
}

public class Tofu extends CondimentDecorator {

    HotSpot hotSpot;

    public Tofu(HotSpot hotSpot) {
        this.hotSpot = hotSpot;
    }

    @Override
    public String getDescription() {
        return hotSpot.getDescription() + "加一份豆腐";
    }

    @Override
    public double cost() {
        return hotSpot.cost() + 10;
    }
}

public class Mutton extends CondimentDecorator {

    HotSpot hotSpot ;
    public Mutton(HotSpot hotSpot) {
        this.hotSpot = hotSpot;
    }

    @Override
    public String getDescription() {
        return hotSpot.getDescription() + "加一份羊肉";
    }

    @Override
    public double cost() {
        return hotSpot.cost() + 58;
    }
}

public class Beaf extends CondimentDecorator {

    HotSpot hotSpot ;
    public Beaf(HotSpot hotSpot) {
        this.hotSpot = hotSpot;
    }

    @Override
    public String getDescription() {
        return hotSpot.getDescription() + "加一份牛肉";
    }

    @Override
    public double cost() {
        return hotSpot.cost() + 48;
    }
}

测试

public class Test {

    public static void main(String[]args){
        //单锅底
        HotSpot hotSpot = new MushroomHotSpot();
        System.out.println(hotSpot.getDescription() + "。价格:" + hotSpot.cost()+"。");
        //一份生菜的鸳鸯锅
        HotSpot hotSpot1 = new TwoFlavorHotPot();
        hotSpot1 = new Lettuce(hotSpot1);
        System.out.println(hotSpot1.getDescription() + "。价格:" + hotSpot1.cost()+"。");
        //样样都有的香辣锅
        HotSpot hotSpot2 = new SpicyHotPot();
        hotSpot2 = new Lettuce(hotSpot2);
        hotSpot2 = new Tofu(hotSpot2);
        hotSpot2 = new Mutton(hotSpot2);
        hotSpot2 = new Beaf(hotSpot2);
        System.out.println(hotSpot2.getDescription() + "。价格:" + hotSpot2.cost()+"。");
        
    }
}

菌菇锅。价格:38.0。
鸳鸯锅加一份生菜。价格:58.0。
香辣锅加一份生菜加一份豆腐加一份羊肉加一份牛肉。价格:184.0。

从上述的测试代码中我们可以看出,我们可以对既有的底锅进行任意菜品的添加,可以在不用修改原有代码的基础上动态生成顾客所需的菜,满足顾客的需求。

总结

优点

缺点

参考

上一篇下一篇

猜你喜欢

热点阅读