Dynamically add alternate processing to objects. 动态地为一个对象添加一些额外的职责,相比生成子类的形式更加灵活。

    • 与 Mixin 类似,它们可以被认为是另一个可行的对象子类化的替代方案。装饰本身对于原类的基本功能来说不是必要的,所以它能够被动态添加至系统现有类的能力。
    • 装饰者,可以修改现有的系统,在系统中为对象添加额外的功能之时,不需要大量修改它们的底层代码。这种模式一般会在需要大量不同类型的对象功能的时候使用。因为创建一个几百种不同类型对象的构造函数是一件可怕的事情。
    • Instance decorator / Class decorator

    动机:希望为对象而不是整个类添加一些功能。

    适用性:

    • 不影响其他类的情况下,以动态、透明的方式给单个对象添加职责。
    • 处理那些可以撤销的职责。
    • 当不能够采用生成子类的方法进行扩充的时候。

    代码结构:

    标准的 Java 式 Decorator

    1. interface Vehicle {
    2. run();
    3. }
    4. class Bus extends Vehicle {
    5. public run() {};
    6. }
    7. class Car extends Vehicle {
    8. public run() {};
    9. }
    10. class EngineDecorator implements Vehicle {
    11. private vehicle: Vehicle;
    12. constructor(vehicle: Vehicle, engineType: string) {
    13. this.vehicle = vehicle;
    14. this.setEngine(engineType);
    15. }
    16. setEngine(engineType: string) {
    17. this.vehicle.engineType = engineType;
    18. }
    19. getEngineSpeed() {}
    20. run() {
    21. this.engineSpeed = this.getEngineSpeed();
    22. this.vehicle.run();
    23. }
    24. }
    25. const myBus = new EngineDecorator(new Bus(), '6g');
    26. const myCar = new EngineDecorator(new Car(), '4g');
    1. function addPrototypeChain(obj) {
    2. obj.prototype.getPrototypeChain = () => {};
    3. obj.prototype.setPrototypeChain = () => {};
    4. return obj;
    5. }
    6. function addDelayExecution(obj) {
    7. obj.delayExecution = () => {};
    8. }
    9. // ES6 Method Decorator
    10. // ES6 Class Decorator
    11. @lazyLoad('image')
    12. class Calendar extends Component {
    13. @deprecated('warning');
    14. doStuff() {
    15. // do stuff
    16. }
    17. }

    实现思路:

    • 满足和装饰的接口的「一致性」。因而 ConcreteDecorator 需要一个父类来保证这种接口的一致性。
    • 改变对象的「外壳」而非「内核」,内核交给 Strategy 模式来处理。

    举例:

    • Java I / O 中,使用 InputStream 作为实例,而 FileInputStream 作为一个 DecoratorInputStream 装饰(扩展)功能,使之具有额外处理文件流的能力。

    效果:

    • 比静态继承更加灵活。
    • 避免在层次结构高层的类有太多的职责。
    • Decorator 是透明包装。
    • 有许多小对象。

    类比:

    • 和 Adapter 不同的是,它强调「扩展」能力,而非「适配」接口。