装饰者设计模式

前言

装饰者模式:动态地将责任附加到对象上,若要扩展功能,装饰者提供了比继承更具有弹性的替代方案。

场景

我们知道,咖啡店里面的口味特别多,有dark roast(深烘焙),也有Espresso(浓缩咖啡),也有Machiatto(马琪雅朵)等等。顾客点咖啡的时候也会顺便点些配料,如牛奶(milK),摩卡(Mocha),配料多达几十种。对于这种场景,如果让我们实现一个订单系统,每一个订单显示顾客点了哪些东西和价格,该如何实现呢?

第一想法

用一个咖啡基类Beverage计算添加调料的总价格,然后各个口味的咖啡类继承该基本类,覆盖cost()方法,并返回父类的调料价格和该口味的价格。

ublic class Beverage {
    public String description; //描述订单定了哪些东西

    public  double cost(){
        double money = 0;
        if (hasMilk()){
            money += 1.0; //加牛奶配料的价格
        }
        if (hasMilk()){
            money += 2.0; //摩卡的价格
        }
        ...
    }

    public boolean hasMilk(){
        ...
    }

    public boolean hasMocha(){
        ...
    }

    ....
}

当顾客点了DarkRost咖啡时:


public class DarkRoast extends Beverage {
    public DarkRoast(){
        description = "Most excellent dark roast";
    }

    @Override
    public double cost() {
        return super.cost() + 2.0; //2.0为单点DarkRoast的价格
    }

    ...
}

这样的订单系统,当调料和口味品种比较少时,是满足需求的。但是当调料多时,父类Beverage中判断该订单是否有某个调料的语句就越来越多,而且有些调料在某些口味中是不可能搭配的确被继承到该口味中。更重要的是,当新增调料的时候,需要在父类添加该调料,这就违反了开发的对扩展开发,对修改封闭的原则。这时候装饰模式就正好解决该问题。

装饰设计模式

当应用装饰设计模式时,当顾客点了一杯DarkRoast,可直接计算出该对象的价格。顾客觉得加点牛奶会更好喝,所以点了一些牛奶加在咖啡上,这时我们只需对DarkRoast对象粉饰一番,将这个对象加上Milk生成新的粉饰对象,新的对象加上milk的价格。最后顾客又点了摩卡,我们对这个新的粉饰对象再进行一番装饰,加上摩卡的价格。这样,这个最终的对象是由DarkRoast不断的被添加新的装饰点形成的。顾客没有要求Soy调料,Soy调料就不会作为装饰点去粉饰DarkRoast对象。总体思路是需要什么,就添加什么,扩展什么。一个对象可以被多个对象进行粉饰包装。用图形象的表示如下:

为了实现这种效果,粉饰对象和被粉饰对象应该同属一个类型,即被粉饰对象DarkRoast和粉饰对象Milk、Mocha继承同一个类。粉饰对象可以获取被粉饰对象的行为并添加上自己的行为。装饰者设计模式总体设计框架如下图所示:

按照这个框架图,来实现我们的代码。先创建一个基类Beverage,它是DarkRoast口味和调料Milk、Mocha共同继承的对象。

public abstract class Beverage {
    public String description;

    public String getDescription(){
        return description;
    }

    public abstract double cost();
}

然后DarkRoast继承Beverage,它是具体被粉饰的对象。


public class DarkRoast extends Beverage {
    public DarkRoast(){
        description = "Most excellent dark roast";
    }

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

}

再创建粉饰对象共同的接口,这个接口也要继承Beverage,以实现粉饰对象和被粉饰对象同属一个类型。


public abstract class CodimentDecorator extends Beverage {
    public abstract String getDescription();

}

粉饰对象共有的接口有了之后,就可以实现具体的实现类了。


public class Milk extends CodimentDecorator {
    private Beverage beverage;

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

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

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


public class Mocha extends CodimentDecorator {
    private Beverage beverage;

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

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

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

每一个粉饰类都有一个Beverage对象,用来传入被粉饰的对象,并对被粉饰的对象加上自己的行为。

最后我们来调试一下:


public class Main {
    public static void main(String[] args){
        Beverage darkRoast = new DarkRoast(); //我点了一杯DarkRoast
        System.out.println(darkRoast.getDescription()+" "+darkRoast.cost());

        darkRoast = new Milk(darkRoast); //老板再来点牛奶
        System.out.println(darkRoast.getDescription()+" "+darkRoast.cost());

        darkRoast = new Mocha(darkRoast); //老板加点Mocha
        System.out.println(darkRoast.getDescription()+" "+darkRoast.cost());
    }
}

最终结果为:

Most excellent dark roast 1.0

Most excellent dark roast, Milk 3.0

Most excellent dark roast, Milk , Mocha 9.0

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值