The Decorator pattern adds behavior to one object by placing it inside a wrapper. The wrapper supports the same interface, so a caller can use either the original object or a decorated one. We can stack wrappers when we need several optional behaviors.
“Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality.”
Consider a support app that produces a short report. Some recipients need a heading, others need a footer, and some need both. We can keep the original report simple and add the requested formatting with decorators.
1. How the Decorator Pattern Works
The pattern has five participants. The common interface makes each wrapper usable wherever the original component is expected.
| Participant | Responsibility |
|---|---|
| Component | Declares the operation that the original object and every wrapper support. |
| Concrete component | Performs the original operation without optional additions. |
| Base decorator | Holds one component through the common interface and delegates the operation to it. |
| Concrete decorators | Add behavior before or after delegating to the wrapped component. |
| Client | Chooses the wrappers and calls the outermost component. |
A decorator is itself a component and holds another component. The held object may be the original component or another decorator. The client builds a stack, then calls its outermost layer. Calls move inward through the layers; a returned value travels outward as each decorator adds its part.

2. Decorator Pattern in Action
Our support app creates a report containing the number of open tickets. SupportReport provides the core text. HeadingReport can place a title above it, FooterReport can add an ending, and UppercaseReport can transform the text it receives. The app selects only the wrappers needed for a particular report.
| Pattern participant | Class or interface | What it does |
|---|---|---|
| Component | Report | Declares text(), the operation every report supports. |
| Concrete component | SupportReport | Returns the original ticket summary. |
| Base decorator | ReportDecorator | Stores one Report and delegates text() to it. |
| Concrete decorators | HeadingReport, FooterReport, UppercaseReport | Add a heading, footer, or uppercase transformation to the wrapped result. |
| Client | DecoratorDemo | Builds the wrapper stack and prints its results. |
For the heading-and-footer report, DecoratorDemo creates new FooterReport(new HeadingReport(original)). A call to text() reaches the outer FooterReport first, then HeadingReport, and finally SupportReport. As the result returns, HeadingReport prepends the title and FooterReport appends the ending. The original object still returns its plain text when called directly.

3. Decorator Pattern Implementation
The complete runnable source on GitHub contains the package declaration, imports, all classes, and the demo entry point. The excerpts below omit those setup details so the wrapper behavior is easier to see.
3.1. Define the shared operation
The Report interface gives callers one way to request report text. SupportReport implements the basic version without optional formatting.
interface Report {
String text();
}
final class SupportReport implements Report {
@Override
public String text() {
return "2 open support tickets";
}
}
3.2. Delegate through the base decorator
ReportDecorator implements Report and stores a wrapped Report. Its text() method delegates by default. The constructor rejects a null wrapped report, so a decorator always has an object to call.
abstract class ReportDecorator implements Report {
protected final Report wrapped;
ReportDecorator(Report wrapped) {
this.wrapped = Objects.requireNonNull(wrapped, "wrapped");
}
@Override
public String text() {
return wrapped.text();
}
}
3.3. Add behavior in individual wrappers
HeadingReport adds a title before the wrapped result. FooterReport adds a line after it. Each calls super.text() to get the text from the component inside it.
final class HeadingReport extends ReportDecorator {
HeadingReport(Report wrapped) {
super(wrapped);
}
@Override
public String text() {
return "Support summary\n" + super.text();
}
}
final class FooterReport extends ReportDecorator {
FooterReport(Report wrapped) {
super(wrapped);
}
@Override
public String text() {
return super.text() + "\nEnd of report";
}
}
The third wrapper converts the result it receives to uppercase. It uses Locale.ROOT so the transformation does not vary with the machine’s default locale. Its constructor follows the same pattern as the two wrappers above.
@Override
public String text() {
return super.text().toUpperCase(Locale.ROOT);
}
4. Demo
From the cloned repository root, compile and run the complete example:
javac -d out src/main/java/com/howtodoinjava/patterns/structural/decorator/DecoratorDemo.java
java -cp out com.howtodoinjava.patterns.structural.decorator.DecoratorDemo
Original: 2 open support tickets
Decorated:
Support summary
2 open support tickets
End of report
Uppercase outside:
SUPPORT SUMMARY
2 OPEN SUPPORT TICKETS
Heading outside:
Support summary
2 OPEN SUPPORT TICKETS
The original line confirms that wrapping has not changed SupportReport. The decorated case combines two additions. Wrapper order matters when one wrapper transforms text added by another: placing UppercaseReport outside HeadingReport capitalizes both lines, while placing HeadingReport outside it leaves the heading unchanged.
5. Similar Patterns and a Java Example
Java’s BufferedInputStream wraps an InputStream and adds buffering. Its inherited close() behavior closes the underlying stream, so the application should treat the wrapper chain as one owned resource.
| Pattern | Deciding difference |
|---|---|
| Adapter | Adapter changes the interface so incompatible objects can work together. Decorator keeps the component interface and adds behavior. |
| Proxy | Proxy controls access to an object; Decorator adds an optional responsibility to the operation. Their class structures may look similar. |
6. FAQs
When is Decorator useful?
Use it when a feature has optional behaviors that must be combined for individual objects. Each wrapper should have a clear job. A large stack can make call order hard to follow, so keep the construction visible and test combinations whose order affects the result.
Does decorating change the original object?
No. The wrapper is a separate object holding a reference to the original or to another wrapper. A direct call on SupportReport still returns the plain ticket summary. A caller that needs the additions must use the outermost wrapper.
Can decorators be rearranged freely?
No. The uppercase demo shows that the outcome can change with nesting order. The wrapper and the object inside it are also separate objects. Code that compares their identities, or calls methods outside the shared Report interface, may therefore behave differently.
7. Conclusion
Decorator lets us assemble optional behavior around one object while preserving a common interface. The support-report example shows where the calls go, how each wrapper changes the returned text, and why the nesting order deserves an explicit test.
Happy Learning!
Thanks Lokesh.. Simple and understandable… And great comment also “Nothing feels better than a sense of being a part of someone’s success” ……. Best of luck to you..
Will AOP proxy be a candidate of Decorator pattern? As it to decorates the existing object with a added functionality
Absolutely yes. It’s correct.
Nice example with simple coding style.
thanks
Stumbled upon your blog sometime back ..Must say it is one of the better blogs clearing java concepts available on web . Really helpful.Hope u keep them coming :)
Nice one Lokesh
Great. Congratulations buddy. Nothing feels better than a sense of being a part of someone’s success.