Definition

Concept

Decorator pattern: structural design pattern. Purpose: attach additional responsibilities to objects dynamically. Alternative to subclassing. Enables flexible and reusable enhancements.

Scope

Applies to runtime behavior extension. Preserves original object interface. Supports recursive composition of decorators. Key in UI frameworks, I/O streams, logging systems.

Classification

Category: Structural pattern. Relation: complements Composite pattern. Often used in conjunction with Factory and Strategy patterns.

Motivation

Problem Statement

Subclassing: rigid, combinatorial explosion of subclasses. Static behavior extension. Maintenance overhead increases exponentially.

Solution Insight

Use composition over inheritance. Wrap objects with decorators providing extra features. Enable dynamic, transparent behavior addition at runtime.

Resulting Benefits

Reduced subclass proliferation. Increased flexibility. Runtime configuration possible. Adheres to Open/Closed Principle.

Structure

Class Diagram

Component interface: defines operations. ConcreteComponent: base object. Decorator: maintains reference to Component, implements Component interface. ConcreteDecorator: adds responsibilities.

Object Diagram

Objects layered: ConcreteComponent wrapped by one or more ConcreteDecorators. Each decorator forwards requests, optionally adds behavior.

UML Notation

Interface and abstract class usage. Aggregation links from Decorator to Component. Recursive composition evident.

ElementRole
ComponentDefines interface for objects
ConcreteComponentImplements Component interface
DecoratorHolds reference to Component, delegates calls
ConcreteDecoratorAdds responsibilities dynamically

Participants

Component

Abstract interface or class. Declares operations. Ensures consistent API for components and decorators.

ConcreteComponent

Defines core functionality. Object to be decorated. Implements Component interface.

Decorator

Abstract class implementing Component. Contains reference to Component. Delegates operations, enabling extension.

ConcreteDecorator

Concrete subclasses adding specific responsibilities. Overrides operations to enhance behavior before/after delegation.

Mechanism

Dynamic Wrapping

Decorator holds component reference. Methods override and extend behavior. Calls forwarded to wrapped object.

Recursive Composition

Decorators can wrap other decorators. Stackable behavior. Enables layering enhancements.

Interface Preservation

Decorators maintain component interface. Transparent to clients. Supports polymorphism.

interface Component { operation(): void;}class ConcreteComponent implements Component { operation() { // core behavior }}class Decorator implements Component { protected component: Component; constructor(component: Component) { this.component = component; } operation() { this.component.operation(); }}class ConcreteDecorator extends Decorator { operation() { // additional behavior before super.operation(); // additional behavior after }}

Advantages

Flexibility

Behavior added/removed at runtime. No static inheritance limitations.

Single Responsibility

Divide concerns into separate decorators. Simplifies maintenance.

Open/Closed Principle

Classes open for extension, closed for modification. Enhancements via decorators.

Composability

Multiple decorators combined in arbitrary order. Reusable components.

Disadvantages

Complexity

Increased number of small classes. Difficult to understand decorator chains.

Debugging Difficulty

Tracing wrapped calls complicated. Stack traces harder to interpret.

Overhead

Runtime wrapping incurs slight performance cost. Increased memory usage.

Identity Issues

Equality checks and type identification complicated by wrappers.

Implementation

Steps

  1. Define Component interface.
  2. Create ConcreteComponent with core behavior.
  3. Implement abstract Decorator holding Component reference.
  4. Derive ConcreteDecorators adding behaviors.
  5. Compose objects by wrapping ConcreteComponent.

Language Considerations

Supports all OOP languages. Dynamic languages simplify implementation. Static languages require interfaces or abstract classes.

Performance Optimization

Minimize decorator layers. Cache results when possible. Avoid excessive wrapping.

StepDescription
Define InterfaceCommon API for components and decorators
ConcreteComponentBase object with original behavior
Abstract DecoratorHolds reference, delegates calls
ConcreteDecoratorAdds new behavior dynamically
CompositionWrap instances to extend functionality

Use Cases

User Interface Components

Adding borders, scrollbars, or shadows to widgets dynamically. Example: Swing decorators.

Input/Output Streams

Java I/O uses decorators for buffering, encryption, compression.

Logging and Auditing

Wrap core services to add logging, validation, or metrics collection.

Security Enhancements

Dynamic authorization checks by decorating service calls.

Comparison with Other Patterns

Decorator vs Proxy

Decorator adds responsibilities, Proxy controls access. Both wrap objects but intent differs.

Decorator vs Adapter

Adapter changes interface, Decorator preserves interface and adds behavior.

Decorator vs Composite

Composite composes objects into tree structures; Decorator adds behavior transparently.

Examples

Java I/O Streams

InputStream, BufferedInputStream, DataInputStream. Wrapping streams to add functionality.

Graphical User Interface

Swing components wrapped by decorators adding borders or effects.

Custom Logging Decorator

class LoggerDecorator extends Decorator { operation() { console.log("Before operation"); super.operation(); console.log("After operation"); }}

Best Practices

Keep Decorators Lightweight

Minimize code in decorators. Delegate most behavior. Enhance only necessary parts.

Use Clear Naming Conventions

Name decorators by the responsibility they add. Improves readability and maintainability.

Limit Decorator Layers

Excessive wrapping complicates debugging. Balance flexibility and complexity.

Document Composition Order

Order of wrapping affects behavior. Explicitly document decorator stacking.

References

  • Gamma, E., Helm, R., Johnson, R., Vlissides, J. Design Patterns: Elements of Reusable Object-Oriented Software, Addison-Wesley, 1994, pp. 175-196.
  • Buschmann, F., Meunier, R., Rohnert, H., Sommerlad, P., Stal, M. Pattern-Oriented Software Architecture, Volume 1: A System of Patterns, Wiley, 1996, pp. 239-272.
  • Freeman, E., Freeman, E., Sierra, K., Bates, B. Head First Design Patterns, O'Reilly Media, 2004, pp. 203-245.
  • Shalloway, A., Trott, J.R. Design Patterns Explained: A New Perspective on Object-Oriented Design, Addison-Wesley, 2004, pp. 107-130.
  • Metz, C. Practical UML Statecharts in C/C++, Elsevier, 2001, pp. 85-98.