Decorator
Also known as: Wrapper
Purpose
Help the user decide whether Decorator is appropriate, then design and apply it to replace inheritance-based behavior extension with composable, stackable wrapper objects.
When To Use
- User asks to explain the Decorator or Wrapper pattern.
- A class has optional behaviors that are being combined through subclassing, leading to a combinatorial explosion.
- Behaviors need to be added to or removed from individual objects at runtime, not the whole class.
- The class to extend is
finalor otherwise closed to inheritance. - Multiple independent optional behaviors need to be composed in arbitrary combinations.
- User wants to layer cross-cutting concerns (logging, caching, compression, encryption, auth) over a core component.
Inputs
- The core component and its interface (the operations clients depend on).
- The set of optional behaviors to attach (each becomes a Concrete Decorator).
- Whether behaviors must be composable in any order, or ordering matters.
- Language constraints (final classes, interface support, decorator language features).
- Whether a base decorator class is worth adding or single-method interfaces make it redundant.
Workflow
- Clarify the goal. Confirm whether the user wants explanation, code review, or implementation/refactor.
- Check applicability. Confirm there are optional behaviors that vary per object instance, not per class. If all objects always get all behaviors, inheritance may be simpler.
- Define the Component interface. Extract the methods shared by the core component and all decorators into a single interface.
- Implement the Concrete Component. Create the base class with default behavior. Keep it focused — no optional logic here.
- Create the Base Decorator.
Implement the Component interface. Hold a
wrappee: Componentreference. Delegate all methods towrappee. This class exists to avoid repeating delegation boilerplate in every Concrete Decorator. - Implement Concrete Decorators.
Each overrides one or more methods, calls
super/wrappeeto get the base result, then adds behavior before or after. - Compose in the Client. Client wraps the Concrete Component in the desired decorators in the needed order. The outermost decorator is what the client interacts with.
- Validate behavior. Confirm each decorator works standalone and in combination. Confirm client code needs no changes when a new decorator is added.
- Explain tradeoffs. Call out stack ordering effects, difficulty removing a mid-stack decorator, and initial wiring verbosity.
Decision Branches
- If the behavior to add does not change the interface (same methods, extra logic): Decorator is a strong fit.
- If the interface itself must change (new methods exposed): Decorator can extend the interface, but clients needing the new methods must know the concrete decorator type — evaluate whether this breaks transparency.
- If only one extra behavior is needed permanently for all instances: Prefer simple subclassing or composition without the full Decorator scaffolding.
- If controlling access, lifecycle, or identity of an object is the goal: Use Proxy instead — structurally similar but different intent.
- If adapting an incompatible interface: Use Adapter — Decorator keeps or extends the same interface.
- If passing requests through a chain where any handler may stop the flow: Use Chain of Responsibility — decorators must not break the request flow.
Output Contract
When responding, provide:
- A concise suitability verdict (why Decorator or why not).
- Named roles mapped to the user's domain (Component interface, Concrete Component, Base Decorator, Concrete Decorators).
- Step-by-step migration plan from current class structure to Decorator.
- A minimal code sketch in the user's language showing wrapping and stacking.
- Validation checklist confirming transparency and composability.
Quality Checks
- All decorators and the Concrete Component implement the same Component interface.
- Base Decorator delegates every method to the wrappee — no logic leaks into it.
- Each Concrete Decorator adds exactly one responsibility.
- Client code works identically whether it holds a plain component or a deeply decorated one.
- Adding a new decorator requires zero changes to existing components or other decorators.
- Decorator stack order is documented where ordering produces different results.
Common Mistakes To Prevent
- Putting business logic in the Base Decorator instead of keeping it as pure delegation.
- Forgetting to delegate methods not being decorated (causing silent behavior drops).
- Making a decorator depend on the concrete type of its wrappee (breaks transparency).
- Confusing Decorator with Proxy: Decorator enriches behavior; Proxy controls access/lifecycle.
- Confusing Decorator with Chain of Responsibility: decorators cannot stop the call chain; CoR handlers can.
- Order-sensitive stacks with no documentation — leads to subtle bugs.
References
- Detailed guide: REFERENCE.md
- Worked examples: EXAMPLES.md