Growing with the Web

Decorator design pattern

Published , updated
Tags:

The decorator pattern allows behaviour to be added to an existing object at runtime. This is achieved by wrapping the object (the component) in another class (the decorator).

Like the delegation pattern, the decorator pattern is similar to inheritance as it extends the functionality of a particular class. The primary difference between decorator and delegation is that the decorator pattern is more flexible, allowing multiple decorators to point to a single component at one time.

Reducing the complexity of an inheritance tree is one of the benefits to this pattern, imagine for example an application that prints a photo with an optional filter, an optional border and an optional rotation. This can be achieved in the following ways:

  • A single class with a lot of code; Photo
  • A class for each combination of options; Photo, BorderPhoto, FilterPhoto, RotatePhoto, BorderFilterPhoto, FilterRotatePhoto, BorderRotatePhoto, BorderFilterRotatePhoto
  • A class with optional decorators; Photo, PhotoFilterDecorator, PhotoBorderDecorator, PhotoRotateDecorator

The decorator pattern is of great use when implementing the open/closed principle, as described below:

software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification

Object-Oriented Software Construction, Bertrand Meyer

So once an application has been built, it should only be extended, not modified. It is particularly useful in a production environment as it reduces the amount of regression testing required. The decorator pattern is great here as it’s simple to extend existing components in a completely modular way.

Benefits

  • Add behaviour to a component dynamically at runtime
  • Attach multiple decorators to a single component at one time
  • Completely modular, we don’t need to touch the existing component
  • Can reduce the amount subclasses of a class

Drawbacks

  • Overuse of the decorator pattern can lead to very abstract and complex code

UML diagram

Decorator UML diagram

Code example

public abstract class Decorator implements ComponentInterface {
    private ComponentInterface component;

    public Decorator(ComponentInterface component) {
        this.component = component;
    }

    protected ComponentInterface getComponent() {
        return component;
    }
}

public interface ComponentInterface {
    public String operation();
}

public class ConcreteComponent implements ComponentInterface {
    public String operation() {
        return "Component operation";
    }
}

public class ConcreteDecorator extends Decorator {
    public ConcreteDecorator(ComponentInterface component) {
        super(component);
    }

    @Override
    public String operation() {
        return "Decorator operation";
    }
}
// file: decorator.js

'use strict';

var Decorator = function (component) {
  this.component = component;
};

Decorator.prototype.operation = function () {
  return this.component.name + ' Decorator.operation';
};

module.exports = Decorator;



// file: component.js

'use strict';

var Component = function (name) {
  this.name = name;
};

Component.prototype.operation = function () {
  return this.name + ' Component.operation';
};

module.exports = Component;

Usage examples

Here are a few examples where you could use the decorator pattern:

  • A photo (component) can be printed normally (concrete component), with a border (decorator), with a filter (decorator) or with a rotation (decorator).
  • An employee (component) can have their name printed with no title (concrete component), as a developer (decorator) or as a manager (decorator).
  • An email’s (component) contents can be constructed normally (concrete component), or with an optional header/footer describing the security level (decorators) or the organisation (decorator).

Like this article?
Subscribe for more!