设计模式学习(五) -- 装饰者模式 Decorator Pattern

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

继承的缺点:类的数量爆炸、设计死板,以及基类加入的新功能不适用所有子类。

利用继承来设计子类的行为,是在编译时静态地决定的,而且所有子类都会继承到相同的行为。用组合扩展对象的行为,就能在运行时动态地扩展行为。而且使用组合,可以动态地组合对象,写新的代码添加新的功能,而不需要修改原来的代码,减少引进bug的风险。

设计原则:类应该对扩展开放,对修改关闭。
允许类容易扩展,在不修改原来代码的情况下,就可以搭配新的行为。

遵循开放-关闭原则,会引入新的抽象层次,增加代码的复杂度,所以需要把精力集中在设计中最有可能改变的地方来使用这一原则。

装饰者模式类图

  • 装饰者和被装饰者有相同的超类型 (利用继承达到类型匹配,而不是为了获取基类行为);
  • 可以用一个或者多个装饰者包装一个对象;
  • 由于有相同的超类,所以任何需要使用被装饰的对象时,都可以用装饰者的对象代替它;
  • 装饰者可以在所委托的被装饰者的行为之前或者之后,加上自己的行为;
  • 被装饰的对象,可以在运行时动态不限量的使用任何装饰者来装饰对象。

装饰者模式实例类图:
装饰者模式实例类图

  • 装饰者CondimentDecorator和被装饰者Expresso、HouseBlend、DarkRoast等具有相同的超类型Beverage。
  • 可以用一个或者多个CondimentDecorator装饰者(如Milk、Mocha、Soy等)来包装一个被装饰对象(如Expresso、HouseBlend、DarkRoast等的对象)。
    例如:
    Beverage beverage = new HouseBlend();
    beverage = new Mocha(beverage); //用Mocha对象来包装HouseBlend对象
  • 装饰者Mocha对象可以在被装饰者HouseBlend对象的cost调用之后加上自己的cost定义的行为(参见代码)
    装饰者对象持有超类型Beverage的引用,这样就可以使用超类型的引用来添加自己的行为。
  • 被装饰者HouseBlend对象可以在运行时动态不限量使用任何装饰者Milk、Mocha、Soy等对象来装饰自己。
    Beverage beverage2 = new HouseBlend(); //HouseBlend对象是被装饰者对象
    beverage2 = new Mocha(beverage2); //被Mocha装饰
    beverage2 = new Soy(beverage2); //被Soy装饰
    beverage2 = new Whip(beverage2); //被Whip装饰

对象被装饰者对象装饰,体现在代码中就是:被装饰者对象 = 装饰者对象;

代码实现:

/**
 *
 * @author Yves
 */
public abstract class Beverage {
    public String description = "Unknown Beverage";

    public String getDescription(){
        return this.description;
    }

    public abstract double cost();
}

超类型Beverage

public class DarkRoast extends Beverage {

    public DarkRoast() {
        super.description = "DarkRoast";
    }

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

被装饰者DarkRoast

public class HouseBlend extends Beverage{

    public HouseBlend(){
        super.description = "House blend coffee";
    }

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

被装饰者HouseBlend

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

装饰者抽象类CondimentDecorator与被装饰者DarkRoast和被装饰者HouseBlend具有相同的超类型Beverage

public class Mocha extends CondimentDecorator{

    Beverage beverage;

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

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

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

装饰者子类Mocha持有超类型Beverage引用,并利用该引用在cost方法中添加自己的行为beverage.cost() + 0.20;

public class Soy extends CondimentDecorator{

    Beverage beverage;

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

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

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

装饰者子类Soy持有超类型Beverage引用,并利用该引用在cost方法中添加自己的行为beverage.cost() + 0.15;

public class Whip extends CondimentDecorator{

    Beverage beverage;

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

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

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

装饰者子类Whip持有超类型Beverage引用,并利用该引用在cost方法中添加自己的行为beverage.cost() + 0.10;

public class StarbuzzCoffee {
    public static void main(String args[]){
        Beverage beverage = new HouseBlend();
        System.out.println(beverage.getDescription() + " $" + beverage.cost());

        Beverage beverage2 = new DarkRoast();    //DarkRoast is the concrete class which can be decorated.
        beverage2 = new Mocha(beverage2);   //Decorate by Mocha
        beverage2 = new Whip(beverage2);    //Decorate by Whip
        System.out.println(beverage2.getDescription() + " $" + beverage2.cost());
    }
}

被装饰者DarkRoast,beverage2.cost() –> 0.99
内圈装饰者Mocha,beverage2.cost() –> 0.20
外圈装饰Whip,beverage2.cost() –> 0.10
最后beverage2.cost()返回结果1.29

run:
House blend coffee $0.89
DarkRoast, Mocha, Whip $1.29

调用关系图:
装饰者模式实例调用关系图

首先调用外层装饰者的cost方法,然后依次调用内层装饰者的cost方法,直到调用被装饰者的cost方法;首先被装饰者cost方法返回,然后最内层装饰者cost方法返回,然后依次返回外层装饰者cost方法,直到最外层装饰者cost方法返回。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值