装饰者模式详解

让我们首先来看一下装饰者模式的定义:

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

看到这个定义我们很容易就能想到两个问题:

  1. 责任是怎么动态地附加在对象上的呢?
  2. 装饰者模式哪里比继承好?

为了得到这两个问题的答案,下面我们就来看看UML图和具体的代码。
这里写图片描述
从上面的UML图可以看到,concreteComponent和Decorator继承了Component,其中concreteComponent是要动态加上新行为的对象,而Decorator则是具体的装饰者的父类,它可以是抽象类,也可以是接口。继承了Decorator的子类们,利用组合拥有component的实例变量(关键!),既可以扩展状态,也可以加上新的方法。

直接看UML图的话可能有点不知所云,接下来结合具体的代码吧。

        Beverage beverage = new Espresso(); //向上转型
        System.out.println(beverage.getDescription() 
                + " $" + beverage.cost());

        Beverage beverage2 = new DarkRoast();
        beverage2 = new Mocha(beverage2);
        beverage2 = new Mocha(beverage2);
        beverage2 = new Whip(beverage2);
        System.out.println(beverage2.getDescription() 
                + " $" + beverage2.cost());
        /// Espresso $1.99
        /// Dark Roast Coffee, Mocha, Mocha, Whip $1.49

我们直接从测试代码开始看,揣摩一下装饰者模式运行的机制。首先第一小段,是我们熟悉的多态,虽然调用的是beverage.getDescription(),但是由于动态绑定(多态),最终调用了Espresso的desciption,cost也是一样的。接下来那一段就有点奇怪了,首先new了一个DarkRoast,然后将实例beverage2放入Mocha的构造器中,然后又“包”了几层,最终调用的结果是怎么出来的?带着这个疑问,我Debug了一下:
这里写图片描述
看到这里就很清晰了,当调用berverage2.getDescription()的时候,这个调用递归地“传导”到最里层DarkRoast

public DarkRoast() {
        description = "Dark Roast Coffee";
    }

调用了其构造器,然后打印出 Dark Roast Coffee(继承了berverage的getDescription方法),紧接着调用了Mocha的getDecription方法

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

以此类推…最终打印出Dark Roast Coffee, Mocha, Mocha, Whip 后面那个价格也是类似的。

文章的最后,我们来回顾一下文章开始的那两个问题,装饰者模式就是通过构造器组合的方式,一层层地“动态地”把责任附加在concreteComponent上,最终让concreteComponent得到了“装饰”,然后装饰者模式这种利用了多态+组合这种方式模拟了继承的功能,但是又没有继承那种会让子类强行拥有其特性的脆弱性,所以说这种模式是很好的替代方案。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值