美文网首页
设计模式之装饰者模式

设计模式之装饰者模式

作者: 戴先森Davi | 来源:发表于2020-01-04 20:01 被阅读0次

装饰者模式

装饰者模式的定义

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

装饰者模式是一种“结构型”模式。

装饰者模式的使用场景

  • 需要透明且动态地扩展类的功能时。

装饰者UML类图

装饰者模式UML.png

角色介绍

  • Component:抽象组件。
    可以是一个接口或抽象类,其充当的就是被装饰的原始对象。

  • ConcreteComponent: 组件具体实现类。
    该类是Component类的基本实现,也是我们装饰的具体对象。

  • Decorator: 抽象装饰者。
    顾名思义,其承担的职责就是为了装饰我们的组件对象,其内部一定要有一个指向组件对象的引用。在大多数情况下,该类为抽象类,需要根据不同的装饰逻辑实现不同的具体子类。当然,如果装饰逻辑单一,只有一个的情况下我们可以省略该类直接作为具体的装饰者。

  • ConcreteDecoratorA: 装饰者具体实现类。
    只是对抽象装饰者作出具体的实现。

  • ConcreteDecoratorB: 同上。
    同上。

例子: HeadFirst一书中 星巴兹饮料例子

星巴兹饮料装饰者模式类图:


image.png

具体代码实现如下:

饮料抽象类:

public abstract class Beverage {
    protected String description = "Unknown Beverage";

    public String getDescription() {
        return description;
    }

    public abstract double cost();
}

黑色烘焙饮料:

public class DarkRoast extends Beverage {

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

    @Override
    public double cost() {
        return .99;
    }

}

脱咖啡因:

public class Decaf extends Beverage {

    public Decaf() {
        description = "Decaf Coffee";
    }

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

浓咖啡:

public class Espresso extends Beverage {
    public Espresso() {
        description = "Espresso";
    }

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

混合咖啡:

public class HouseBlend extends Beverage {
    public HouseBlend() {
        description = "House Blend Coffee";
    }

    @Override
    public double cost() {
        return .89;
    }
}

调味品装饰者抽象类:

public abstract class CondimentDecorator extends Beverage {

    @Override
    public abstract String getDescription();

}

具体装饰者:牛奶

public class Milk extends CondimentDecorator {
    private Beverage beverage;

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

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

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

具体装饰者:摩卡

public class Mocha extends CondimentDecorator {
    private Beverage beverage;

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

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

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

具体装饰者:豆浆

public class Soy extends CondimentDecorator {
    private Beverage beverage;

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

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

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

具体装饰者:奶泡

public class Whip extends CondimentDecorator {
    private Beverage beverage;

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

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

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

测试下我们的程序

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

        // 制造 DarkRoast(双倍摩卡奶泡咖啡)
        Beverage beverage2 = new DarkRoast();
        beverage2 = new Mocha(beverage2); // 使用 mocha 装饰它
        beverage2 = new Mocha(beverage2); // 使用第二个 mocha 装饰它
        beverage2 = new Whip(beverage2); // 使用 whip 装饰它
        System.out.println(beverage2.getDescription() + " $" + beverage2.cost());


        Beverage beverage3 = new HouseBlend();
        beverage3 = new Soy(beverage3);
        beverage3 = new Mocha(beverage3);
        beverage3 = new Whip(beverage3);
        System.out.println(beverage3.getDescription()
                + " $" + beverage3.cost());
    }
}

测试结果:

Espresso 1.99 Dark Roast Coffee, Mocha, Mocha, Whip1.49
House Blend Coffee, Soy, Mocha, Whip $1.34

总结

  • 继承属于扩展形式之一,但不见得是达到弹性设计的最佳方
    式。
  • 在我们的设计中,应该允许行为可以被扩展,而无须修改现有的代码。
  • 组合和委托可用于在运行时动态地加上新的行为。
  • 装饰者模式意味着一群装饰者类,这些类用来包装具体组件。
  • 装饰者类反映出被装饰的组件类型(事实上,他们具有相同的类型,都经过接口或继承实现)。
  • 你可以用无数个装饰者包装一个组件。
  • 装饰者一般对组件的客户是透明的,除非客户程序依赖于组件的具体类型。

优点

  • 除了继承,装饰者模式也可以让我们扩展行为。
  • 装饰者可以在被装饰者的行为前面与/或后面加上自己的行为,甚至将被装饰者的行为整个取代掉,而达到特定的目的。

缺点

  • 装饰者会导致设计中出现许多小对象,如果过度使用,会让程序变得很复杂。

Android源码中的装饰者模式实现

  • ContextWrapper

参考资料
《Head First 设计模式》
《Android 源码设计模式解析与实战》

相关文章

  • JavaScript 设计模式核⼼原理与应⽤实践 之 结构型设计

    JavaScript 设计模式核⼼原理与应⽤实践 之 结构型设计模式 装饰器模式,又名装饰者模式。它的定义是“在不...

  • Java设计模式之 —— 装饰者(Decorator) — 点

    Java设计模式之 —— 装饰者(Decorator) — 点炒饭 下面会用做炒饭的例子来描述一下装饰者设计模式,...

  • 设计模式

    设计模式 单例模式、装饰者模式、

  • 设计模式笔记汇总

    目录 设计原则 “依赖倒置”原则 未完待续... 设计模式 设计模式——策略模式 设计模式——装饰者模式 设计模式...

  • java IO 的知识总结

    装饰者模式 因为java的IO是基于装饰者模式设计的,所以要了解掌握IO 必须要先清楚什么事装饰者模式(装饰者模式...

  • 设计模式

    常用的设计模式有,单例设计模式、观察者设计模式、工厂设计模式、装饰设计模式、代理设计模式,模板设计模式等等。 单例...

  • 设计模式之装饰者模式

    如果你没了解过装饰者模式,那么请继续往下看,如果你是老司机,那么,你可以快速往下看。 开始装个13,再进入正文。 ...

  • 设计模式之装饰者模式

    该模式可以避免滥用继承,在使用对象组合的方式,就能做到在运行时装饰类,此后便能在不修改任何底层代码的情况下给对象赋...

  • 设计模式之装饰者模式

    装饰者模式的定义是动态地给一个对象添加一些额外的职责。就增加功能来说,装饰者模式比生成子类更加灵活。 通常给一个对...

  • 设计模式之装饰者模式

    前言: 相信Java开发者在使用java i/o API的时候,对于以下代码写法应该非常熟悉: 在不知道具体设计实...

网友评论

      本文标题:设计模式之装饰者模式

      本文链接:https://www.haomeiwen.com/subject/xanlnctx.html