Java Omnibus
OOAD & Architecture / GoF patterns / Structural / Decorator Pattern in Java
GoF Structural Java Order Management
GoF Pattern

Decorator helps when behavior should be added flexibly around an object without subclassing every combination.

Attach additional responsibilities to an object dynamically while keeping the same interface visible to clients.

Intent

What the pattern is trying to do

Attach additional responsibilities to an object dynamically while keeping the same interface visible to clients.

Problem

What force creates the need

Optional or combinable behavior keeps growing, and inheritance would require too many subclasses to represent every variation.

Solution

How the pattern responds

Wrap the object with decorator layers that implement the same interface and add behavior before or after delegation.

Structure

How the moving parts fit together

A component interface is implemented by the core object and by decorators that hold another component and extend behavior through delegation.

Java Example

Java example in the Order Management domain

Decorator Pattern in Java example
package org.javaomnibus.ecommerce.gof.structural;

public interface CheckoutStep {
    void run(Order order);
}

public final class CoreCheckoutStep implements CheckoutStep {
    @Override
    public void run(Order order) {}
}

public abstract class CheckoutStepDecorator implements CheckoutStep {
    protected final CheckoutStep next;

    protected CheckoutStepDecorator(CheckoutStep next) {
        this.next = next;
    }
}

public final class AuditCheckoutStep extends CheckoutStepDecorator {
    public AuditCheckoutStep(CheckoutStep next) {
        super(next);
    }

    @Override
    public void run(Order order) {
        next.run(order);
        audit(order);
    }

    private void audit(Order order) {}
}
Code Walkthrough

Step by step

  1. CoreCheckoutStep provides the base behavior.
  2. AuditCheckoutStep preserves the same interface while layering extra work.
  3. Multiple decorators can be stacked without exploding subclasses.
  4. Decorator is strongest when the force is optional layered behavior rather than access control or translation.
When To Use

Where this pattern helps

  • When behavior should be added selectively and in combinations
  • When inheritance would create too many variant subclasses
When Not To Use

When a simpler design is better

  • When behavior does not need to be layered dynamically
  • When the wrapper is actually about access mediation or interface translation instead
Trade-Offs

What this pattern costs

  • Many small wrappers can make debugging call paths harder
  • The order of decorators can affect behavior and must be designed carefully
Modern Relevance

How this fits today

Decorator remains highly relevant in Java for I/O streams, middleware chains, observability layers, and optional business behavior around stable contracts.

Common Misuse

Where teams get it wrong

Using Decorator when a wrapper changes access rules or translates interfaces confuses it with Proxy or Adapter and weakens the design discussion.

Related Patterns

Compare with nearby choices


What To Read Next