设计模式-装饰者模式

设计模式有一个重要的原则:类对扩展开放,对修改关闭。装饰者模式对喜欢继承的人来说是一个新的设计眼界,但却是再熟悉不过了。有这样一个例子:

冲泡咖啡:

1、拿一个深焙咖啡来冲泡。

2、感觉咖啡太苦了,放点摩卡修饰它,味道好多了。

3、可是我还想加些奶泡装饰它,这样就更好看了。

4、最后在付款的时候价格也会增加。

上面的例子展示的是我们对咖啡进行扩展的过程。目的是为了说明我们要允许类容易扩展,在不修改现有代码的情况下,就可以搭配新的行为。这样的设计具有弹性可以应对改变,可以接受新的功能来应对改变的需求。但是如何设计才能实现可以扩展,有又禁止修改呢?

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


下面我们看一个代码例子。

对咖啡做扩展后就该称为饮料(Beverage)了

//定义成抽象类
public abstract class Beverage{
    String description="Cafe Beverage";
    //在此做了实现
    public String getDescription(){
        return description;
    }
    //在子类中做具体实现
    public abstract double cost();
}
Beverage很简单。我们再来实现调料(Condiment)抽象类,也就是装饰者类:
public abstract class CondimentDecorator extents Beverage{
    //所有的调料装饰者都必须重新实现getDescription()方法。为啥呢?稍后会知晓。
    public abstract String getDescription();
}

已经有了饮料基础类,让我们先实现一个加糖饮料(SugarCaffee)。

public class AddSugarCaffee extends Beverage{
    public AddSugarCaffee(){
        decription="SugarCaffee";
    }
    public double cost(){
        return 1.99;
    }
}
再定义另一种饮料--奶泡(AddMilkCaffee) .

public class AddMilkCaffee extends Beverage{
    //这种饮料喝SugarCafe做法一样,只是修改了配方,相应的描述也做一下修改。
    public AddMochaCaffee(){
        decription="MochaCaffee";
    }
    public double cost(){
        return 0.98;
    }
}

如果你回头去看看装饰者模式的类图,将发现我们已经完成了抽象组件(Beverage),有了具体组件(AddSagarCaffee和 AddMilkCaffee ),也有了抽象装饰者( CondimentDecorator )。现在,我们就来实现具体装饰者.

Mocha是一个装饰者,所以扩展自CondimentDecorator,别忘了CondimentDecorator也扩展自Beverage。

public class Mocha extends CondimentDecorator{
    //用一个实例变量记录饮料,也就是被装饰者
    Beverage beverage;

    //把饮料当做构造器的参数,再由构造器将此饮料记录在实例变量中。
    public Mocha(Beverage beverage){
        this.beverage=beverage;
    }

    public String getDescription(){
        //我们希望描述不只是描述饮料,而是完整地连调料都描述出来。所以先用委托的做法,得到一个叙述。
        //然后在其后加上附加的调料。把之前加过的调料都可以打印出来。
        return beverage.getDescription()+",Mocha";
    }
    public double cost(){
        //0.20为Mocha调料的价钱。
        return 0.20+beverage.cost;
    }
}

同样在定义一个大豆Soy装饰者。也扩展自 CondimentDecorator。

public class Soy extends CondimentDecorator{
    Beverage beverage;

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

    public String getDescription(){
        return beverage.getDescription()+",Soy";
    }
    public double cost(){
        return 0.20+beverage.cost;
    }
}

现在各种调料都有了,我们实例化一个对象,然后用调料来装饰它。

public  class StarbuzzCaffee{
    public static void main(String args[]){
        Beverage beverage=new AddSugarCaffee();
        //打印出只加入一次糖的咖啡饮料。
        System.out.println(beverage.getDescription()+"$"+beverage.getCost());

        Beverage beverage2=new AddMilkCaffee();
        beverage2==new Mocha(beverage2);//第一次加入摩卡,用摩卡装饰
        beverage2=new Mocha(beverage2);//第二次加入摩卡
        beverage2=new Soy(beverage2);//在两次加入摩卡的基础上,再加入大豆装饰。
        //打印出来的结果将是“Mocha Mocha Soy $  0.8”
        System.out.println(beverage2.getDescription+"$"+beverage2.getCost);
    }
}


装饰者该做的事,就是增加行为到包装对象上。在平时开发中遇到的I/O流(FileInputStream,BufferedInputStream,LineNumberInputStream,BufferInputStreamReader等),就是经典的装饰者模式。

继承属于扩展形式之一,但不见得是达到弹性设计的最佳方式。在我们的设计中,应该允许行为可以被扩展,而无须修改现有的代码。装饰者模式可以在被装饰者的行为前面与后面加上自己的行为,甚至将被装饰者的行为整个取代,而达到特定的目的。你可以用无数个装饰者包装一个组件,但是,这也会导致设计中出现许多小对象,如果过度使用,反而让程序变得很复杂。

总之:装饰者模式提倡,类,应该对扩展开放,对修改关闭。

上图:最直观!


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值