Also known as Wrapper

Decorator

Intent

Attach new behaviors to objects by placing them inside wrapper objects that contain these behaviors.

Problem

You have to add and remove responsibilities from an object dynamically, but do it in a way so that it stay compatible with the rest of application's code.

Inheritance is the first solution that comes to mind when you need to extend class behaviors. However, the inheritance is static. You can't add new subclasses to a program when it's already compiled and executed.

Solution

The decorator pattern relies on special objects called decorators (or wrappers). They have the same interface as an object that they suppose to wrap, so the client code won't notice when you hand it a wrapper instead of the original object.

All wrappers have a field for storing an instance of an original object. Most wrappers initialize that field with an object passed into their constructor.

So how do they dynamically change the behavior? As I mentioned, wrappers have the same interface as the target objects. When you call a decorator's method, it executes the same method in a wrapped object and then adds something to the result. It can also be called before the original method, but that's up to the business logic.

Here's the interesting part: you can wrap an object with a decorator... and then wrap the result with another decorator, and so on. The resulting behavior will be a combination of all decorators and the original object.

Real-World Analogy

Clothing

Wearing clothes is an example of using decorators. When you're cold, you wrap yourself with a sweater. If it's still cold, you can wear a jacket on top. If it's raining, you can put on a raincoat.

All of these garments "extend" your basic behavior, but are not part of you. Therefore you can easily take them off whenever you don't need them anymore.

Structure

Decorator pattern structure
  1. Component defines a common interface for both wrappers and wrapped objects.

  2. Concrete Component is a class that contains basic behavior that can be altered by decorators.

  3. Base Decorator contains a field for storing wrapped objects. The field should be defined with a Component type to support both Concrete Components and Decorators. Base decorator delegates all operations to a wrapped object.

  4. Concrete Decorators contain extra behaviors that can be dynamically added to the components. Decorators may execute their behavior either before or after calling the same method in wrapped object.

Pseudocode

In this example, Decorator helps to protect financial data with encryption implicitly to the existing code. Application wraps the financial object with an encryption and compression decorators, that return plain data when reading from disk, but encrypt and compress data when writing it back.

Both decorators and the financial class have a common interface that makes them interchangeable for a client code.

// Common interface for all components.
interface DataSource is
    method writeData(data)
    method readData():data

// One of the concrete components can act as a base layer.
class FileDataSource implements DataSource is
    constructor FileDataSource(filename) { ... }

    method writeData(data) is
        Write data to file.

    method readData():data is
        Read data from file.

// All other concrete components may act as wrappers.
class DataSourceDecorator implements DataSource is
    field wrappee: DataSource

    constructor DataEncyptionDecorator(source: DataSource) is
        wrappee = source

    method writeData(data) is
        wrappee.writeData(data)

    method readData():data is
        return wrappee.readData()

// Concrete Decorators extend the functionality of a component they wrap.
class EncyptionDecorator extends DataSourceDecorator is
    method writeData(data) is
        Encrypt passed data.
        Pass the compressed data to wrappee's writeData() method.

    method readData():data is
        Get the data from wrappee's readData() method.
        Decrypt and return that data.

// You can wrap objects in several layers of decorators.
class CompressionDecorator extends DataSourceDecorator is
    method writeData(data) is
        Compress passed data
        Pass the compressed data to wrappee's writeData() method.

    method readData():data is
        Get the data from wrappee's readData() method.
        Uncompress and return that data.


// Option 1. A simple example of decorator assembly.
class Application is
    method dumbUsageExample() is
        source = new FileDataSource('somefile.dat')
        source.writeData(salaryRecords)
        // a file with plain data

        source = new CompressionDecorator(source)
        source.writeData(salaryRecords)
        // compressed file

        source = new EncyptionDecorator(source)
        source.writeData(salaryRecords)
        // compressed and encrypted file



// Option 2. Client code, which uses an external data source. SalaryManager
// neither knows not cares about data storage specifics. It receives already
// configured data source.
class SalaryManager is
    field source: DataSource

    constructor SalaryManager(source: DataSource) { ... }

    method load() is
        return source.readData()

    method save() is
        source.writeData(salaryRecords)
    // ...Other useful methods...


// Application can assemble objects with a different set of functionality using
// the same decorators at run time, depending on the configuration
// or environment.
class ApplicationConfigurator is
    method configurationExample() is
        source = new FileDataSource("salary.dat");
        if (enabledEncryption)
            source = new EncyptionDecorator(source)
        if (enabledCompression)
            source = new CompressionDecorator(source)

        logger = new SalaryLogger(source)
        salary = logger.load();
    // ...Rest of an application code.

Applicability

When you need to dynamically assign the behaviors to objects without breaking the code that uses these objects.

The Decorator pattern allows assigning new behaviors to objects dynamically and implicitly to a client code. Objects can be wrapped with multiple wrappers at the same time, resulting in a stacking behavior of all wrappers.

When it's not possible or awkward to extend the object behavior with inheritance.

Many programming languages have a final keyword that can be used to prevent further extension of a class. When dealing with such code, the only option for the extension would be to use the Decorator pattern.

How to Implement

  1. Make sure that your task can be represented as one primary component and several optional extensions over it.

  2. Create the Component interface that should describe all common methods for that primary component ant its extensions.

  3. Create the Concrete Component class and put the primary business logic in it.

  4. Create the Base Decorator class. Create a field for storing wrapped objects. It should have a Component interface type to allow storing both components and decorators inside.

  5. Make sure that all classes implement the Component interface.

  6. Make all the methods of the Base Decorator delegating execution to the methods of the wrapped object. It will allow Concrete Decorators to extend only a portion of the component's behavior and leave the rest intact.

  7. Create Concrete Decorator classes by extending them from the Base Decorator.

  8. A Concrete Decorator should execute its behavior prior or after the call to the same method in a wrapped object (you can just call a parent's method since it will end up calling the wrapped method).

  9. Client code must be responsible for configuring layers of wrapping. Client should work with all classes through a Component's interface to make the decorators interchangeable.

Pros and Cons

  • Much more flexible than class inheritance.
  • Allows adding and removing behaviors in runtime.
  • Allows combining several additional behaviors by using multiple wrappers.
  • Allows composing complex objects from simple ones instead of having monolithic classes that implement every variant of behavior.
  • It's hard to configure a multi-wrapped object.
  • Lots of small classes.

Relations with Other Patterns

  • Adapter provides a different interface to its subject. Proxy provides the same interface. Decorator provides an enhanced interface.

  • Adapter is meant to change the interface of an existing object. Decorator enhances another object without changing its interface. Decorator is thus more transparent to the application than an adapter is. As a consequence, Decorator supports recursive composition, which isn't possible with pure Adapters.

  • Chain of Responsibility and Decorator have very common class structures. They both rely on the recursive composition to pass execution through a series of objects. But there are also several crucial differences.

    The Chain of Responsibility handlers can execute arbitrary actions, independent of each other. They can also terminate further chaining of the request at will. On the other hand, various Decorators extend a particular behavior and suppose to keep its interface consistent. Also, Decorators are not allowed to break the execution chain at will.

  • Composite and Decorator have similar structure diagrams since they both rely on recursive composition to organize an open-ended number of objects.

    Decorator can be viewed as a degenerate Composite with only one component. However, Decorator adds additional responsibilities to the object while Composite just "summs up" of the same behavior executed over its children.

    But they can also cooperate: Composite can use Decorator to change behavior of the tree components.

  • Designs that make heavy use of the Composite and Decorator patterns often can benefit from Prototype as well. It would allow to clone complex structures, instead of re-constructing them from scratch.

  • Decorator lets you change the skin of an object. Strategy lets you change the guts.

  • Decorator and Proxy have similar structures but different purposes. Both patterns built on the composition principle of delegating work to other object. However, the Proxy manages the life cycle of its service object by itself, whereas Decorator structure is controlled by client.

Implementations in Different Programming Languages

Java