Implement Java decorators by wrapping a small interface, delegating cleanly, and keeping each added behavior narrow and explicit.
Decorator: A wrapper that adds behavior to an object while keeping the same client-facing contract.
Decorator is strongest in Java when behavior is optional, order-sensitive, and easier to express as wrapping than as subclass inheritance.
1public interface ReportRenderer {
2 String render(Report report);
3}
A concrete component provides the base behavior:
1public final class BaseReportRenderer implements ReportRenderer {
2 @Override
3 public String render(Report report) {
4 return report.body();
5 }
6}
1public abstract class ReportRendererDecorator implements ReportRenderer {
2 protected final ReportRenderer delegate;
3
4 protected ReportRendererDecorator(ReportRenderer delegate) {
5 this.delegate = delegate;
6 }
7}
8
9public final class AuditingRenderer extends ReportRendererDecorator {
10 public AuditingRenderer(ReportRenderer delegate) {
11 super(delegate);
12 }
13
14 @Override
15 public String render(Report report) {
16 System.out.println("Rendering report " + report.id());
17 return delegate.render(report);
18 }
19}
The key rule is simple: the decorator should preserve the contract and add one clear piece of behavior around delegation.
Decorator is a strong fit for:
Decorator becomes a problem when:
If that happens, the design probably wants a pipeline, interceptor chain, or explicit orchestration object instead.