Decorator

Intent

  • Dynamically add a behavior to an object.

  • Propose a flexible alternative to inheritance.

Motivation

  • Occasionally, we want to add a behavior only to certain objects of a class.

decorator example
Gamma'95

Motivation - Example (1/2)

decorator classes

Motivation - Example (2/2)

decorator instances

Applicability (1/2)

  • Use the decorator pattern when you want to:

  • add a behavior to an object dynamically and transparently.

  • add a behavior that can be removed later.

Applicability (2/2)

  • Use the decorator pattern when the creation of subclasses is impractical.

Structure

decorator structure
  • /Component: the object we want to add behavior to

  • /Decorator: the object that adds behavior to the component.

Consequences

  • More flexible than inheritance.

  • Prevents the creation of complex/heavy classes on the top of a class hierarchy.

  • Components and decorators are not identical: comparison may not work as expected.

  • Explosion of small objects.

Implementation Tradeoffs

  • Interface conformance: components and decorators must implement the same interface.

  • Omission of the abstract Decorator class.

  • Lightweight component classes: since decorators specialize the component, the latter should have the less properties as possible.

Authors and Date

  • «Design Patterns: Elements of Reusable Object-Oriented Software.» Erich Gamma, Richard Helm,Ralph Johnson, and John Vlissides. Addison Wesley. October 1994.

More Examples

Starbuzz Coffee (1/3)

starbuzz problem

Starbuzz Coffee (2/3)

starbuzz class explosion

Starbuzz Coffee (3/3)

starbuzz decorator

Decorators in the Java I/O package

java input stream
InputStream is = new FileInputStream(file);
DataInputStream dis = new DataInputStream(is);
BufferedInputStream bis = new BufferedInputStream(dis);

FilterInputStream.java

public class FilterInputStream extends InputStream {
    protected volatile InputStream in;

    protected FilterInputStream(InputStream in) {
        this.in = in;
    }

    public int read() throws IOException {
        return in.read();
    }

	//(...)

Decorators in the Java Collections Framework

Diagram
Figure 1. Java Collections Framework

Decorator Usage

Decorator Creation
Collection<String> tags = new ArrayList();
Collection<String> synchronizedTags = Collections.synchronizedCollection(tags);
Collection<String> readOnlyTags = Collections.unmodifiableCollection(tags);


Factory Method Implementation (JDK 15)
public static <T> Collection<T> synchronizedCollection(Collection<T> c) {
    return new SynchronizedCollection<>(c);
}

Java «SynchronizedCollection»

Implementation (JDK 15)
static class SynchronizedCollection<E> implements Collection<E>, Serializable {
    final Collection<E> c;  // Backing Collection
    final Object mutex;     // Object on which to synchronize

    SynchronizedCollection(Collection<E> c) {
        this.c = Objects.requireNonNull(c);
        mutex = this;
    }

    public int size() {
        synchronized (mutex) {return c.size();}
    }
    public boolean isEmpty() {
        synchronized (mutex) {return c.isEmpty();}
    }
    // (...)
}

Decorator