likes
comments
collection
share

设计模式--装饰者模式

作者站长头像
站长
· 阅读数 15

一 简介

装饰者模式(decorator pattern): 属于结构型设计模式。动态地将责任附加到对象上, 若要扩展功能, 装饰者提供了比继承更有弹性的替代方案。

二 意图

为对象动态添加功能: 允许你通过将对象放入包含行为的特殊封装对象中来为原对象绑定新的行为。

三 结构

装饰者(Decorator)和具体组件(ConcreteComponent)都实现了接口组件(Component),具体组件的方法实现不需要依赖于其它对象,而装饰者聚合了一个组件,这样它可以装饰其它装饰者或者具体组件。所谓装饰,就是把这个装饰者套在被装饰者之上,从而动态扩展被装饰者的功能。装饰者的方法有一部分是自己的,这属于它的功能,然后调用被装饰者的方法实现,从而也保留了被装饰者的功能。可以看到,具体组件应当是装饰层次的最低层,因为只有具体组件的方法实现不需要依赖于其它对象。

设计模式--装饰者模式

Component:组件声明封装器和被封装对象的公用接口。

ConcreteComponent:具体组件 是被封装对象所属的类。它定义了基础行为,但装饰类可以改变这些行为。

Decorator:装饰者基类 拥有一个指向被封装对象的引用成员变量。该变量的类型应当被声明为通用部件接口, 这样它就可以引用具体的部件和装饰。 装饰基类会将所有操作委派给被封装的对象。

ConcreteDecorator(A B...):具体装饰类定义了可动态添加到组件的额外行为。具体装饰类会重写装饰基类的方法, 并在调用父类方法之前或之后进行额外的行为。

四 代码实现

设计不同种类的饮料,饮料可以添加配料,比如可以添加牛奶,并且支持动态添加新配料。每增加一种配料,该饮料的价格就会增加,要求计算一种饮料的价格。

组件:Component

public interface Beverage {
    double cost();
}

具体组件:ConcreteComponent

public class DarkRoast implements Beverage {
    @Override
    public double cost() {
      return 1;
    }
}

装饰者基类:Decorator

public abstract class CondimentDecorator implements Beverage {
    protected Beverage beverage;
}

具体装饰类:ConcreteDecorator(A B...)

public class Milk extends CondimentDecorator {
    public Milk(Beverage beverage) {
        this.beverage = beverage;
    }
    @Override
    public double cost() {
        return 1 + beverage.cost();
    }
}
public class Mocha extends CondimentDecorator {
    public Mocha(Beverage beverage) {
        this.beverage = beverage;
    }
    @Override
    public double cost() { 
        return 1 + beverage.cost();
    }
}

客户类调用:

public class Client {
    public static void main(String[] args) {
        Beverage beverage = new DarkRoast();
        beverage =new Mocha(beverage);
        beverage =new Milk(beverage);
        System.out.println(beverage.cost());
    }
}

五 总结

优点

  • 无需创建新子类即可扩展对象的行为。
  • 可以在运行时添加或删除对象的功能。
  • 可以用多个装饰封装对象来组合几种行为。
  • 单一职责原则。 可以将实现了许多不同行为的一个大类拆分为多个较小的类。

缺点

  • 在封装器栈中删除特定封装器比较困难。
  • 实现行为不受装饰栈顺序影响的装饰比较困难。
  • 各层的初始化配置代码看上去可能会很糟糕。

使用场景

  • 如果希望在无需修改代码的情况下即可使用对象,且希望在运行时为对象新增额外的行为,可以使用装饰者模式。
  • 如果用继承来扩展对象行为的方案难以实现或者根本不可行(比如:使用 final修饰的某个类),可以使用该模式。