Applying the Decorator Pattern in Spring Boot: Multi‑Layer Decoration Example
This tutorial demonstrates how to integrate the Decorator design pattern into a Spring Boot application, showing a basic interface, concrete services, a simple decorator, and a multi‑layer decorator with full code examples and runtime output.
This article explains how to apply the Decorator pattern within a Spring Boot project, providing a step‑by‑step practical example.
The Decorator (or Wrapper) pattern allows additional responsibilities to be added to an object dynamically without modifying its original code, offering a more flexible alternative to inheritance.
In plain terms, it lets you combine extra behavior with existing business logic without touching the original implementation.
The example defines an ISurfTheInternetService interface representing an online‑surfing service, and two concrete implementations: FadInternetCafe (a fashionable internet cafe) and RetroInternetBar (a retro internet bar), each printing a simple message.
public interface ISurfTheInternetService {
void doSurfing();
}
@Service("fadInternetCafeService")
public class FadInternetCafe implements ISurfTheInternetService {
@Override
public void doSurfing() {
System.out.println("在时尚 网咖 ,网上冲浪咯~");
}
}
@Service("retroInternetBarService")
public class RetroInternetBar implements ISurfTheInternetService {
@Override
public void doSurfing() {
System.out.println("在复古 网吧 ,网上冲浪咯~");
}
}A controller method /doTest autowires both services and calls doSurfing() to show the basic behavior.
@Autowired @Qualifier("fadInternetCafeService")
ISurfTheInternetService fadInternetCafeService;
@Autowired @Qualifier("retroInternetBarService")
ISurfTheInternetService retroInternetBarService;
@GetMapping("/doTest")
public void doTest() {
fadInternetCafeService.doSurfing();
retroInternetBarService.doSurfing();
}The SurfDecorator class implements the same interface and holds a reference to an ISurfTheInternetService instance. Its doSurfing() method adds extra logging before delegating to the wrapped service.
public class SurfDecorator implements ISurfTheInternetService {
private ISurfTheInternetService surfTheInternetService;
public SurfDecorator(ISurfTheInternetService surfTheInternetService) {
this.surfTheInternetService = surfTheInternetService;
}
@Override
public void doSurfing() {
System.out.println("SurfDecorator 模拟业务 增强器在玩一点很新的东西...");
surfTheInternetService.doSurfing();
System.out.println("SurfDecorator 模拟业务 增强器在玩一点很新的东西,比如说是XXXX");
}
}The controller now creates SurfDecorator instances for each service and calls doSurfing() , showing the enhanced output.
@GetMapping("/useDecoratorTest")
public void useDecoratorTest() {
SurfDecorator fadDecorator = new SurfDecorator(fadInternetCafeService);
fadDecorator.doSurfing();
SurfDecorator retroDecorator = new SurfDecorator(retroInternetBarService);
retroDecorator.doSurfing();
}To illustrate multi‑layer decoration, a RechargeDecorator extends SurfDecorator and overrides doSurfing() to invoke the parent behavior and then execute an additional checkRecharge() method.
public class RechargeDecorator extends SurfDecorator {
public RechargeDecorator(ISurfTheInternetService surfTheInternetService) {
super(surfTheInternetService);
}
@Override
public void doSurfing() {
super.doSurfing();
checkRecharge();
}
private void checkRecharge() {
System.out.print("RechargeDecorator 也在增强,看看这个货卡里面充了有多少,就来上网");
}
}A new endpoint /moreDecoratorTest wraps a SurfDecorator with a RechargeDecorator , demonstrating stacked decorators.
@GetMapping("/moreDecoratorTest")
public void moreDecoratorTest() {
SurfDecorator base = new SurfDecorator(retroInternetBarService);
RechargeDecorator recharge = new RechargeDecorator(base);
recharge.doSurfing();
}The series of screenshots in the original article confirm that each level of decoration executes in order, showing how responsibilities can be layered without modifying the original service classes.
In summary, the article provides a complete, runnable example of applying single and multi‑layer Decorator patterns in a Spring Boot backend, illustrating how to extend functionality cleanly and non‑intrusively.
Selected Java Interview Questions
A professional Java tech channel sharing common knowledge to help developers fill gaps. Follow us!
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.