SpringBoot 中 12 种设计模式应用案例,个个都能让你项目提档升级!
你说现在这开发呀,真不容易。以前写个CRUD能混饭吃,现在是写着写着你发现,一个接口写五遍都不带重样的——为啥?需求千奇百怪,模块贼多,场景一套一套的……这时候你再不学点“套路”,项目真就栽沟里去了。
设计模式这玩意儿,说白了就是老前辈踩坑踩出来的“套路”。咱用 SpringBoot 做开发,它不光能写 API,能接消息,能搞分布式,能接微服务,还能把这些老套路藏在项目各个角落里用得贼溜。
今天我就给你掏心窝子地整12个SpringBoot 项目中真能用得上的设计模式实战案例,每一个我都自己用过、踩过、优化过,咱别搞纸上谈兵,真刀真枪拉出来说事。
1. 单例模式:Spring 本体就自带的“老黄牛”
说单例,咱不可能不提 Spring 里最核心那一套——Bean 管理。其实你平时注入的 @Service
、@Component
啥的,它背后用的就是单例模式,默认都是一个实例干到死那种。
但有时候我们自己写个工具类、工厂类,也想整成全局一个实例,比如一个“配置管理器”。
场景:自定义一个配置读取器,只初始化一次,所有人共用
💡 实战代码:
public class AppConfigManager {
// volatile 是为了防止指令重排,保证线程安全
private static volatile AppConfigManager instance;
private Properties properties;
private AppConfigManager() {
properties = new Properties();
try {
properties.load(new FileInputStream("app-config.properties"));
} catch (IOException e) {
System.out.println("读取配置失败啦,哥!"); // 嘴碎输出
}
}
public static AppConfigManager getInstance() {
if (instance == null) {
synchronized (AppConfigManager.class) {
if (instance == null) {
instance = new AppConfigManager();
}
}
}
return instance;
}
public String get(String key) {
return properties.getProperty(key);
}
}
👀这玩意就是典型的“双重校验锁单例”,咱在 SpringBoot 里虽然不常自己造轮子,但这类场景,比如搞个日志中心、配置桥接器,照样能用!
2. 工厂模式:Spring 用它整了一锅 Bean
工厂这词一听就熟,@Bean
不就是“工厂方法”干的事?但是咱也得学会自己写工厂类,啥时候用?——比如你想根据不同的“类型”,动态创建不同的策略实现。
如果你近期准备面试跳槽,建议在ddkk.com在线刷题,涵盖 一万+ 道 Java 面试题,几乎覆盖了所有主流技术面试题,还有市面上最全的技术五百套,精品系列教程,免费提供。
场景:用户行为埋点,按类型创建不同的日志策略
💡 实战代码:
public interface LogStrategy {
void record(String msg);
}
public class FileLogStrategy implements LogStrategy {
public void record(String msg) {
System.out.println("写入文件日志:" + msg);
}
}
public class DBLogStrategy implements LogStrategy {
public void record(String msg) {
System.out.println("插入数据库日志:" + msg);
}
}
public class LogStrategyFactory {
public static LogStrategy create(String type) {
if ("file".equals(type)) {
return new FileLogStrategy();
} else if ("db".equals(type)) {
return new DBLogStrategy();
} else {
throw new IllegalArgumentException("不认识的日志类型啊兄弟!");
}
}
}
使用:
LogStrategy strategy = LogStrategyFactory.create("file");
strategy.record("用户点击了某个按钮");
👋以后你要接三方支付、搞抽奖、定制短信策略、搞个推送机制啥的,这种工厂+策略是你爹!
3. 代理模式:Spring AOP 的老祖宗
你写过切面吧?写过 @Transactional
吧?都知道背后是代理搞的鬼。代理模式就是在“你干活前后”,我给你悄悄包一层小动作,你以为你在调用原始方法,其实被“盯上了”。
场景:拦截某个Service方法,在调用前后打印点东西(模拟日志)
💡 实战代码:
public interface OrderService {
void placeOrder(String product);
}
public class OrderServiceImpl implements OrderService {
public void placeOrder(String product) {
System.out.println("下单成功:" + product);
}
}
// 静态代理类
public class LogProxyOrderService implements OrderService {
private final OrderService target;
public LogProxyOrderService(OrderService target) {
this.target = target;
}
public void placeOrder(String product) {
System.out.println("【日志】准备下单:" + product);
target.placeOrder(product);
System.out.println("【日志】下单完成:" + product);
}
}
使用:
OrderService service = new LogProxyOrderService(new OrderServiceImpl());
service.placeOrder("iPhone 20");
⚠️说白了,这就像饭店门口那个迎宾,帮你开门、点个头,真正的事还是你自己干,但这个“门面”能帮你搞点“前戏+收尾”,贼实用。
4. 策略模式:登录方式一变,接口不改,策划喊你爹!
你看看现在这登录方式,都成精了,什么短信验证码、微信扫码、邮箱验证、账号密码、三方 OAuth2,恨不得都塞到一个 /login
里头去,咋办?改接口?你疯啦?!
用“策略模式”呗!
场景:用户登录系统支持多种方式(邮箱、短信、微信)
💡 实战代码:
// 登录策略接口
public interface LoginStrategy {
boolean login(String identifier, String credential);
}
// 邮箱登录实现
public class EmailLoginStrategy implements LoginStrategy {
@Override
public boolean login(String identifier, String credential) {
System.out.println("邮箱登录验证中..." + identifier);
return "123456".equals(credential);
}
}
// 短信登录实现
public class SmsLoginStrategy implements LoginStrategy {
@Override
public boolean login(String identifier, String credential) {
System.out.println("短信验证码验证中..." + identifier);
return "654321".equals(credential);
}
}
// 策略上下文
public class LoginContext {
private LoginStrategy strategy;
public void setStrategy(LoginStrategy strategy) {
this.strategy = strategy;
}
public boolean execute(String id, String code) {
return strategy.login(id, code);
}
}
使用:
LoginContext context = new LoginContext();
// 设置为短信登录
context.setStrategy(new SmsLoginStrategy());
boolean result = context.execute("13333333333", "654321");
System.out.println("登录结果:" + result);
👀 你想换登录方式?换个实现就行,控制层连屁都不用动;后端这玩意能顶十个前端小哥的活!
5. 观察者模式:新订单一来,短信微信都给我响
你还别说,有时候老板要求一个下单操作,要通知十几个系统,客服、发货、库存、短信、微信、站内信都得一起轰炸,就问你一句:你写十个 service.send()
?
不,那是体力活!要干技术活,就得整观察者模式!
场景:用户下单成功后,系统自动推送多路通知(库存、物流、客服)
💡 实战代码:
// 观察者接口
public interface OrderObserver {
void onOrderCreated(String orderId);
}
// 发短信的
public class SmsObserver implements OrderObserver {
public void onOrderCreated(String orderId) {
System.out.println("发送短信通知,订单号:" + orderId);
}
}
// 发微信的
public class WechatObserver implements OrderObserver {
public void onOrderCreated(String orderId) {
System.out.println("发送微信通知,订单号:" + orderId);
}
}
// 被观察者
public class OrderSubject {
private List<OrderObserver> observers = new ArrayList<>();
public void addObserver(OrderObserver observer) {
observers.add(observer);
}
public void createOrder(String orderId) {
System.out.println("订单创建完成:" + orderId);
for (OrderObserver observer : observers) {
observer.onOrderCreated(orderId);
}
}
}
使用:
OrderSubject subject = new OrderSubject();
subject.addObserver(new SmsObserver());
subject.addObserver(new WechatObserver());
subject.createOrder("ORD123456");
🧨 这种一触发多连发的骚操作,在微服务里贼有用,你搞个 RabbitMQ + @EventListener,就是这老哥的兄弟变种,灵!
6. 装饰者模式:加点小料,功能增强了还不破原功能
这模式特别适合那种“在原有功能上偷偷摸摸加点料”的需求,比如你想在原服务的基础上,增加个计时功能、打个日志、做个安全校验……但是你又不能去改原代码。
来——装饰器安排!
场景:统计 Service 方法耗时,不侵入原功能
💡 实战代码:
public interface UserService {
void doSomething();
}
public class RealUserService implements UserService {
public void doSomething() {
System.out.println("业务逻辑处理中...");
try {
Thread.sleep(300); // 假装干点活
} catch (InterruptedException e) {}
}
}
// 装饰器,加耗时统计
public class TimeCostUserService implements UserService {
private final UserService delegate;
public TimeCostUserService(UserService delegate) {
this.delegate = delegate;
}
public void doSomething() {
long start = System.currentTimeMillis();
delegate.doSomething();
long end = System.currentTimeMillis();
System.out.println("耗时:" + (end - start) + "ms");
}
}
使用:
UserService service = new TimeCostUserService(new RealUserService());
service.doSomething();
你看,加功能加得贼自然,像是“原地升级”一样,干干净净(虽然咱说不要干净😂),改都不用改原类,客户一看都得竖拇指!
7. 模板方法模式:通用流程我定,细节你爱咋搞咋搞
你要是经常写那种“导出 Excel”、“生成报告”、“统一审批流”之类的功能,你就知道——90%的逻辑都一毛一样,就只有那 10% 是不同的字段、不同的业务数据。
这时候要是不用模板方法,那你就等着复制粘贴一百遍吧,到最后真能被自己绕晕。
场景:导出不同类型的数据表,但通用导出结构一致
💡 实战代码:
// 抽象模板
public abstract class AbstractExporter {
// 导出逻辑主流程,final 不让子类动
public final void export() {
connect();
List<String> data = fetchData();
writeToExcel(data);
close();
}
protected void connect() {
System.out.println("连接数据库");
}
// 抽象方法,子类去实现
protected abstract List<String> fetchData();
protected void writeToExcel(List<String> data) {
System.out.println("写入 Excel:" + data);
}
protected void close() {
System.out.println("关闭连接");
}
}
// 用户导出
public class UserExporter extends AbstractExporter {
protected List<String> fetchData() {
return Arrays.asList("用户A", "用户B", "用户C");
}
}
// 订单导出
public class OrderExporter extends AbstractExporter {
protected List<String> fetchData() {
return Arrays.asList("订单X", "订单Y", "订单Z");
}
}
使用:
new UserExporter().export();
new OrderExporter().export();
👊 一套流程我说了算,你只要补那个“不同的玩意儿”,不用动脑子改主流程,项目大了后贼省事。
8. 责任链模式:一人一个坑儿,验证全靠排队
你写接口校验的时候,是不是经常要验证 N 多字段?每次都是 if...else
套娃,脑袋都给你整麻了。其实那就是你缺个“责任链”——一个验证器搞一件事,串起来就完事。
如果你近期准备面试跳槽,建议在ddkk.com在线刷题,涵盖 一万+ 道 Java 面试题,几乎覆盖了所有主流技术面试题,还有市面上最全的技术五百套,精品系列教程,免费提供。
这模式一用,校验逻辑简直像排队打饭一样,有条不紊,谁也不抢谁的活儿。
场景:用户注册流程中,手机号、密码、验证码各自校验,按顺序执行,哪错就断
💡 实战代码:
// 抽象处理器
public abstract class Validator {
protected Validator next;
public Validator linkWith(Validator next) {
this.next = next;
return next;
}
public boolean validate(String data) {
if (!check(data)) {
return false;
}
if (next != null) {
return next.validate(data);
}
return true;
}
protected abstract boolean check(String data);
}
// 手机号校验
public class PhoneValidator extends Validator {
protected boolean check(String data) {
System.out.println("校验手机号...");
return data.startsWith("13"); // 假装校验
}
}
// 密码校验
public class PasswordValidator extends Validator {
protected boolean check(String data) {
System.out.println("校验密码...");
return data.length() > 6;
}
}
使用:
Validator chain = new PhoneValidator();
chain.linkWith(new PasswordValidator());
boolean ok = chain.validate("13999999999");
System.out.println("最终校验结果:" + ok);
🤌 校验流程一条龙,想加谁就插进来,想跳谁就甩掉,优雅得一批,维护还贼轻松。
9. 享元模式:资源共享到极致,能省一个对象就不多造
这玩意就是那种“抠门到骨子里”的模式。咱搞项目时,尤其是大量复用小对象(比如图标、颜色、池化资源)的时候,一个个 new 简直就是找死。
享元模式说得直白点:你别重复造,能复用就复用,统一管着点儿!
场景:重复使用大量图标对象、连接对象等,统一池化管理
💡 实战代码:
public class Icon {
private final String name;
public Icon(String name) {
System.out.println("创建图标对象:" + name);
this.name = name;
}
public void display() {
System.out.println("显示图标:" + name);
}
}
public class IconFactory {
private static final Map<String, Icon> cache = new HashMap<>();
public static Icon getIcon(String name) {
if (!cache.containsKey(name)) {
cache.put(name, new Icon(name));
}
return cache.get(name);
}
}
使用:
Icon icon1 = IconFactory.getIcon("用户");
Icon icon2 = IconFactory.getIcon("订单");
Icon icon3 = IconFactory.getIcon("用户"); // 复用
icon1.display();
icon2.display();
icon3.display();
🧠 看明白没?你以为你拿了 3 个“用户”图标,其实只有一个是真的,另外俩是“回锅肉”。
着!
10. 构建者模式(Builder Pattern):参数一多就脑壳疼?来个建造工!
你有没有遇到那种构造函数十几个参数、搞得你都忘了哪个是哪个的场景?还得照顺序传值,搞错一个就全炸。尤其是那种配置类、创建表单字段、拼 JSON 的时候。
这时候就得上构建者模式,谁用谁真香!
场景:构造一个用户注册对象,字段一堆,还不能缺
💡 实战代码:
public class RegisterForm {
private String username;
private String password;
private String email;
private String phone;
// 私有构造方法
private RegisterForm() {}
// Builder 内部类
public static class Builder {
private final RegisterForm form = new RegisterForm();
public Builder username(String username) {
form.username = username;
return this;
}
public Builder password(String password) {
form.password = password;
return this;
}
public Builder email(String email) {
form.email = email;
return this;
}
public Builder phone(String phone) {
form.phone = phone;
return this;
}
public RegisterForm build() {
// 校验也能写在这
if (form.username == null || form.password == null) {
throw new IllegalArgumentException("哥,用户名密码不能空!");
}
return form;
}
}
@Override
public String toString() {
return "注册用户:" + username + ", " + email + ", " + phone;
}
}
使用:
RegisterForm form = new RegisterForm.Builder()
.username("zhangsan")
.password("123456")
.email("zhangsan@example.com")
.phone("13812345678")
.build();
System.out.println(form);
👊 参数不再乱套,字段缺啥一目了然,调试起来贼省事儿,配置项多的项目根本离不开它!
11. 中介者模式(Mediator Pattern):别再互相发消息了,统一让中介来!
这玩意你听着像租房子才用,其实在系统里用处大着呢——当你发现多个模块/组件之间开始疯狂互相调用,每个模块都知道彼此存在,改动一个全炸锅,那你就得赶紧收拢逻辑,用个“中介”。
场景:聊天室中多个用户发送消息,通过中介转发
💡 实战代码:
// 抽象中介者
public interface ChatRoom {
void sendMessage(String from, String to, String msg);
}
// 中介实现
public class WeChatRoom implements ChatRoom {
private Map<String, User> users = new HashMap<>();
public void register(User user) {
users.put(user.name, user);
user.setChatRoom(this);
}
public void sendMessage(String from, String to, String msg) {
User receiver = users.get(to);
if (receiver != null) {
receiver.receive(from, msg);
} else {
System.out.println("【系统】:用户[" + to + "]不在线~");
}
}
}
// 同事类
public class User {
String name;
private ChatRoom chatRoom;
public User(String name) {
this.name = name;
}
void setChatRoom(ChatRoom chatRoom) {
this.chatRoom = chatRoom;
}
public void send(String to, String msg) {
chatRoom.sendMessage(this.name, to, msg);
}
public void receive(String from, String msg) {
System.out.println("【" + from + "对" + name + "说】: " + msg);
}
}
使用:
WeChatRoom room = new WeChatRoom();
User zhang = new User("张三");
User li = new User("李四");
room.register(zhang);
room.register(li);
zhang.send("李四", "晚上撸串不?");
li.send("张三", "带酒没?");
💬 看明白了没?本来“用户 A -> B -> C -> D”乱得一批,现在全走中介,解耦、清晰、扩展性都上去了。
12. 状态模式(State Pattern):一套状态逻辑,全靠对象扛
有些业务状态多得一批,比如订单状态、审核流程、任务执行流转,光靠 if-else 嵌套你能写到破防。而状态模式说白了就是每个状态一个类,你跳哪个状态就换哪个类。
场景:订单状态处理(下单 → 支付 → 发货 → 收货)
💡 实战代码:
// 状态接口
public interface OrderState {
void next(OrderContext ctx);
void printStatus();
}
// 下单状态
public class CreatedState implements OrderState {
public void next(OrderContext ctx) {
ctx.setState(new PaidState());
}
public void printStatus() {
System.out.println("订单已创建,待支付");
}
}
// 已支付状态
public class PaidState implements OrderState {
public void next(OrderContext ctx) {
ctx.setState(new ShippedState());
}
public void printStatus() {
System.out.println("订单已支付,待发货");
}
}
// 发货状态
public class ShippedState implements OrderState {
public void next(OrderContext ctx) {
ctx.setState(new CompletedState());
}
public void printStatus() {
System.out.println("已发货,待收货");
}
}
// 已完成
public class CompletedState implements OrderState {
public void next(OrderContext ctx) {
System.out.println("订单已完成,不能再流转咯!");
}
public void printStatus() {
System.out.println("订单已收货,交易完成");
}
}
// 状态上下文
public class OrderContext {
private OrderState state;
public OrderContext() {
this.state = new CreatedState();
}
public void setState(OrderState state) {
this.state = state;
}
public void nextState() {
state.next(this);
}
public void printStatus() {
state.printStatus();
}
}
使用:
OrderContext ctx = new OrderContext();
ctx.printStatus(); // 创建
ctx.nextState();
ctx.printStatus(); // 支付
ctx.nextState();
ctx.printStatus(); // 发货
ctx.nextState();
ctx.printStatus(); // 完成
ctx.nextState(); // 已完成,不再转移
👊 一步一个状态,啥逻辑在哪儿一清二楚,后续再加个“退货”状态都不用碰原逻辑,直接加类!
整整12招设计模式,真·全套保命工具箱!
咱到这为止,整了一共12个设计模式,每一个都不是扯淡、不是唬人,是干出来的血经验:
模式 | 场景关键词 |
---|---|
单例模式 | 配置缓存、日志控制 |
工厂模式 | 动态创建策略 |
代理模式 | 日志、AOP、权限拦截 |
策略模式 | 登录方式、短信发送、支付逻辑 |
观察者模式 | 下单通知、消息广播 |
装饰者模式 | 统计、增强功能、动态包裹 |
模板方法模式 | 通用流程、数据导出、多类统一结构 |
责任链模式 | 表单验证、权限审批、流程管控 |
享元模式 | 图标复用、连接池、对象池 |
构建者模式 | 表单构造、配置类生成、字段管理 |
中介者模式 | 组件解耦、聊天室、消息协调 |
状态模式 | 审核流转、订单流程、任务状态管理 |
你真要能把这12个全掌握了,项目里90%的重复逻辑都能优化得漂漂亮亮的,老油条们才不靠暴力 if-else 解决一切——他们用套路!