告别烂代码!SpringBoot 设计模式通关秘籍:13 招搞定复杂业务
设计模式这玩意儿,说白了就是程序员前辈们踩坑踩出来的 “祖传经验包”—— 专门解决软件开发里那些反复出现的破问题。
而在 SpringBoot 框架里,设计模式简直是 “隐身大佬”,悄咪咪藏在各个角落:既让框架变得灵活好扩展,又给咱们开发者递上了 “优雅解题剧本”,不用自己瞎琢磨重复造轮子。
今天就给大家扒一扒13 种设计模式在 SpringBoot 里的实战玩法,每种模式都配了能直接跑的代码 + 真实应用场景,新手也能一看就会,老鸟看完直接封神!
1. 单例模式(Singleton Pattern)
模式概述
主打一个 “独苗政策”:确保一个类这辈子只生一个实例,还得给全局留个 “访问入口”,谁要都给同一个。
SpringBoot 实战场景
SpringBoot 里的 Bean 默认就是 “独苗”!由 Spring 容器统一创建、管理,保证全项目上下用的都是同一个对象 —— 比如你在 Controller 和 Service 里注入的 UserService,压根就是同一个 “打工人”。
代码示例(直接 CV)
@Service
public class UserService {
// 私有构造器:防着外人随便new,主打一个“垄断”
private UserService() {
System.out.println("UserService实例上线打工啦~");
}
// Bean默认就是单例,不用额外配置
@Autowired
private UserRepository userRepository;
public User findById(Long id) {
return userRepository.findById(id).orElse(null);
}
}
@RestController
public class UserController {
// 注入的是UserService的“独苗”实例
@Autowired
private UserService userService;
@GetMapping("/users/{id}")
public User getUser(@PathVariable Long id) {
return userService.findById(id);
}
}
实战优势
省内存: 不用反复 new 对象,减少 “内存垃圾”
好管理: 共享资源(比如数据库连接)统一掌控,不混乱
易追踪: 全项目就一个实例,排查问题不用到处找
2. 工厂方法模式(Factory Method Pattern)
模式概述
相当于 “对象生产流水线”:定义一个 “造对象” 的接口,具体造哪种对象,让子类自己说了算 —— 父类只负责 “发号施令”,不插手具体 “生产”。
SpringBoot 实战场景
SpringBoot 的 BeanFactory 就是典型的 “工厂老板”!专门负责创建和管理 Bean 实例,你要啥 Bean,跟它说一声,它就给你造(或拿)一个,不用你自己 new。
代码示例(支付场景专用)
// 支付处理器接口:相当于“生产规范”
public interface PaymentProcessor {
void processPayment(double amount);
}
// 具体实现1:信用卡支付(流水线1号)
@Component("creditCard")
public class CreditCardProcessor implements PaymentProcessor {
@Override
public void processPayment(double amount) {
System.out.println("正在用信用卡支付 $" + amount + ",刷起来~");
}
}
// 具体实现2:PayPal支付(流水线2号)
@Component("paypal")
public class PayPalProcessor implements PaymentProcessor {
@Override
public void processPayment(double amount) {
System.out.println("正在用PayPal支付 $" + amount + ",境外消费走起~");
}
}
// 支付工厂:“流水线调度中心”
@Component
public class PaymentProcessorFactory {
// 自动注入所有PaymentProcessor实现,存成Map(key是@Component的value)
@Autowired
private Map<String, PaymentProcessor> processors;
// 按需“调流水线”
public PaymentProcessor getProcessor(String type) {
PaymentProcessor processor = processors.get(type);
if (processor == null) {
throw new IllegalArgumentException("没找到[" + type + "]类型的支付方式,别瞎输!");
}
return processor;
}
}
// 订单服务:用工厂拿支付处理器
@Service
public class OrderService {
@Autowired
private PaymentProcessorFactory processorFactory;
public void placeOrder(String paymentType, double amount) {
// 要啥支付方式,让工厂给你找
PaymentProcessor processor = processorFactory.getProcessor(paymentType);
processor.processPayment(amount);
// 后续订单处理...
}
}
实战优势
解耦: 调用方(OrderService)不用知道具体是哪种支付,只管 “付钱”
易扩展: 新增支付方式(比如微信支付),只需要加个实现类,不用改旧代码(符合 “开闭原则”)
统一管理: 对象创建逻辑全放工厂里,不乱套
3. 抽象工厂模式(Abstract Factory Pattern)
模式概述
“超级工厂” 升级版:不止造一个对象,而是造一整套 “相关联的对象家族”—— 比如造数据库,不仅造连接(Connection),还造事务(Transaction),保证一套对象 “配套能用”。
SpringBoot 实战场景
SpringBoot 的多环境配置、数据源创建,全靠它!比如开发环境用 MySQL,生产环境用 PostgreSQL,切换环境时,一套 “数据库相关对象”(连接、事务)全切换,不用改代码。
代码示例(多数据源切换)
// 抽象产品1:数据库连接
public interface Connection {
void connect();
void executeQuery(String query);
void close();
}
// 抽象产品2:数据库事务
public interface Transaction {
void begin();
void commit();
void rollback();
}
// 抽象工厂:定义“造一套产品”的规范
public interface DatabaseFactory {
Connection createConnection();
Transaction createTransaction();
}
// 具体工厂1:MySQL工厂(造MySQL的连接和事务)
@Component("mysqlFactory")
@ConditionalOnProperty(name = "db.type", havingValue = "mysql") // 配置文件里db.type=mysql时生效
public class MySQLDatabaseFactory implements DatabaseFactory {
@Override
public Connection createConnection() {
return new MySQLConnection();
}
@Override
public Transaction createTransaction() {
return new MySQLTransaction();
}
}
// 具体工厂2:PostgreSQL工厂(造PostgreSQL的连接和事务)
@Component("postgresFactory")
@ConditionalOnProperty(name = "db.type", havingValue = "postgres") // 配置文件里db.type=postgres时生效
public class PostgresDatabaseFactory implements DatabaseFactory {
@Override
public Connection createConnection() {
return new PostgresConnection();
}
@Override
public Transaction createTransaction() {
return new PostgresTransaction();
}
}
// 具体产品实现:MySQL连接(省略MySQLTransaction、PostgresConnection等实现)
public class MySQLConnection implements Connection {
@Override
public void connect() {
System.out.println("正在连接MySQL数据库,冲!");
}
@Override
public void executeQuery(String query) {
System.out.println("在MySQL上执行SQL:" + query);
}
@Override
public void close() {
System.out.println("关闭MySQL连接,拜拜~");
}
}
// 使用抽象工厂
@Service
public class QueryService {
private final DatabaseFactory databaseFactory;
// 注入指定的工厂(比如mysqlFactory)
@Autowired
public QueryService(@Qualifier("mysqlFactory") DatabaseFactory databaseFactory) {
this.databaseFactory = databaseFactory;
}
public void executeQuery(String query) {
Connection connection = databaseFactory.createConnection();
Transaction transaction = databaseFactory.createTransaction();
try {
connection.connect();
transaction.begin();
connection.executeQuery(query);
transaction.commit(); // 成功就提交
} catch (Exception e) {
transaction.rollback(); // 失败就回滚
} finally {
connection.close(); // 不管成功失败,都关连接
}
}
}
实战优势
成套创建: 相关对象一起造,保证兼容性(比如 MySQL 连接配 MySQL 事务,不会乱配)
环境切换方便: 改个配置文件,整套数据源就切换,不用改业务代码
扩展性强: 新增数据库类型(比如 Oracle),只需要加一个具体工厂和对应的产品实现
4. 建造者模式(Builder Pattern)
模式概述
“复杂对象组装大师”:把复杂对象的 “构建过程” 和 “最终样子” 分开,同一个构建过程,能组装出不同的 “成品”—— 比如拼乐高,同样的步骤,能拼出不同的造型。
SpringBoot 实战场景
SpringBoot 的配置类、链式 API(比如 Lambda 表达式里的链式调用),全是它的身影!比如构建一个复杂的邮件对象(有收件人、抄送、附件、主题等),用建造者模式一步步组装,清晰又不易出错。
代码示例(邮件发送场景)
// 产品类:邮件对象
@Data
public class EmailMessage {
private String from; // 发件人
private List<String> to; // 收件人
private List<String> cc; // 抄送
private String subject; // 主题
private String body; // 正文
private boolean html; // 是否是HTML格式
private List<String> attachments; // 附件
private LocalDateTime scheduledTime; // 定时发送时间
// 私有构造器:只能通过Builder创建
private EmailMessage() {}
// 建造者类:专门负责“组装”邮件
public static class Builder {
private EmailMessage message;
public Builder() {
message = new EmailMessage();
message.to = new ArrayList<>();
message.cc = new ArrayList<>();
message.attachments = new ArrayList<>();
}
// 链式调用:每一步都返回自己,方便连续设置
public Builder from(String from) {
message.from = from;
return this;
}
public Builder to(String to) {
message.to.add(to);
return this;
}
public Builder cc(String cc) {
message.cc.add(cc);
return this;
}
public Builder subject(String subject) {
message.subject = subject;
return this;
}
public Builder body(String body) {
message.body = body;
return this;
}
public Builder html(boolean html) {
message.html = html;
return this;
}
public Builder attachment(String attachment) {
message.attachments.add(attachment);
return this;
}
public Builder scheduledTime(LocalDateTime scheduledTime) {
message.scheduledTime = scheduledTime;
return this;
}
// 组装完成,返回最终邮件对象(还会做参数校验)
public EmailMessage build() {
if (message.from == null || message.to.isEmpty() || message.subject == null) {
throw new IllegalStateException("发件人、收件人、主题是必填项,别偷懒!");
}
return message;
}
}
}
// 邮件服务:用建造者组装邮件
@Service
public class EmailService {
public void sendWelcomeEmail(User user) {
// 一步步组装邮件,像拼乐高一样简单
EmailMessage message = new EmailMessage.Builder()
.from("noreply@example.com")
.to(user.getEmail())
.subject("欢迎加入我们的平台~")
.body("<h1>欢迎你," + user.getName() + "!</h1><p>感谢注册,一起搞事情~</p>")
.html(true) // 支持HTML格式
.build();
sendEmail(message);
}
private void sendEmail(EmailMessage message) {
// 发送邮件逻辑
System.out.println("正在发送邮件:" + message);
}
}
实战优势
参数可控: 一步步设置参数,不用记一堆构造器参数的顺序(再也不用面对new Email(from, to, cc, subject, …)的噩梦)
可读性强: 链式调用像 “说话” 一样,一看就知道在组装什么
支持多配置: 同一个 Builder,能组装出不同参数的对象(比如有的邮件有附件,有的没有)
5. 原型模式(Prototype Pattern)
模式概述
“对象复制粘贴大师”:不重新 new 对象,而是通过 “复制” 一个现有对象(原型)来创建新对象 —— 适合那些 “创建成本高” 的对象(比如初始化要查数据库、加载大量配置)。
SpringBoot 实战场景
SpringBoot 的prototype Bean scope 就是它的实现!每次注入prototype类型的 Bean,都会创建一个新实例 —— 相当于 “复制” 了原型对象,再按需修改。
代码示例(报表配置场景)
// 报表配置类(支持克隆,相当于“原型”)
@Component
@Scope("prototype") // 标记为原型Bean,每次注入都new一个新的
public class ReportConfiguration implements Cloneable {
private String reportType; // 报表类型
private List<String> columns; // 报表列
private String sortBy; // 排序字段
private boolean ascending; // 是否升序
private String dateRange; // 日期范围
// 默认构造器:设置基础配置(原型的默认样子)
public ReportConfiguration() {
this.reportType = "summary";
this.columns = new ArrayList<>(Arrays.asList("id", "name", "date"));
this.sortBy = "date";
this.ascending = false;
this.dateRange = "last7days";
}
// 克隆方法:深拷贝(避免列表等引用类型“共用”)
@Override
public ReportConfiguration clone() {
try {
ReportConfiguration clone = (ReportConfiguration) super.clone();
clone.columns = new ArrayList<>(this.columns); // 深拷贝列表
return clone;
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
// getter和setter方法(省略)
}
// 报表工厂:用原型模式创建报表配置
@Service
public class ReportFactory {
// 注入原型Bean(每次注入都是新的,但这里用来当“默认模板”)
@Autowired
private ReportConfiguration defaultConfig;
// 存储预定义的报表模板(复制原型后修改的)
private Map<String, ReportConfiguration> templates = new HashMap<>();
// 项目启动时初始化模板(复制原型,再自定义)
@PostConstruct
public void initTemplates() {
// 财务报表模板:复制默认原型,再修改配置
ReportConfiguration financialTemplate = defaultConfig.clone();
financialTemplate.setReportType("financial");
financialTemplate.setColumns(Arrays.asList("id", "amount", "transaction_date", "category"));
financialTemplate.setSortBy("amount");
templates.put("financial", financialTemplate);
// 用户活动报表模板:同样复制原型,再修改
ReportConfiguration activityTemplate = defaultConfig.clone();
activityTemplate.setReportType("activity");
activityTemplate.setColumns(Arrays.asList("user_id", "action", "timestamp", "ip_address"));
activityTemplate.setSortBy("timestamp");
templates.put("activity", activityTemplate);
}
// 根据模板创建新配置(复制模板,再按需修改)
public ReportConfiguration createFromTemplate(String templateName) {
ReportConfiguration template = templates.get(templateName);
if (template == null) {
throw new IllegalArgumentException("没找到[" + templateName + "]模板,别瞎输!");
}
return template.clone();
}
// 创建默认配置(直接复制原型)
public ReportConfiguration createDefault() {
return defaultConfig.clone();
}
}
// 报表控制器:使用原型模式生成报表
@RestController
@RequestMapping("/reports")
public class ReportController {
@Autowired
private ReportFactory reportFactory;
@GetMapping("/financial")
public String generateFinancialReport(@RequestParam Map<String, String> params) {
// 拿财务报表模板,再根据请求参数自定义
ReportConfiguration config = reportFactory.createFromTemplate("financial");
// 比如根据请求参数修改日期范围
if (params.containsKey("dateRange")) {
config.setDateRange(params.get("dateRange"));
}
// 生成报表...
return "财务报表生成成功,配置:" + config;
}
}
实战优势
省时间: 不用反复执行初始化逻辑(比如查数据库),复制一下就好
模板复用: 预定义模板,后续创建新对象只需 “复制 + 微调”
减少子类: 不用为了不同配置创建一堆子类,复制原型就能实现差异化
6. 适配器模式(Adapter Pattern)
模式概述
“接口翻译官”:把一个类的接口,转换成另一个接口客户端能接受的样子 —— 相当于手机充电器的转接头,Type-C 接口的充电器,用转接头就能给 iPhone 充电。
SpringBoot 实战场景
SpringBoot 的 MVC 框架、第三方接口集成,全靠它 “搭桥”!比如老系统的支付接口(参数是 accountNumber、amount),新系统要用新接口(参数是 PaymentRequest),用适配器转一下,老接口就能在新系统里用。
代码示例(新旧支付系统对接)
// 老支付系统接口( legacy = 老旧的,难用的 )
public interface LegacyPaymentService {
boolean processPayment(String accountNumber, double amount, String currency);
String getTransactionStatus(String transactionId);
}
// 老支付系统实现(祖传代码,不能动)
@Service("legacyPaymentService")
public class LegacyPaymentServiceImpl implements LegacyPaymentService {
@Override
public boolean processPayment(String accountNumber, double amount, String currency) {
System.out.println("用老系统处理支付,别嫌慢~");
// 老系统的支付逻辑(祖传代码,不敢改)
return true;
}
@Override
public String getTransactionStatus(String transactionId) {
// 老系统查支付状态的逻辑
return "COMPLETED";
}
}
// 新支付系统接口(现代、优雅)
public interface ModernPaymentGateway {
PaymentResponse pay(PaymentRequest request);
TransactionStatus checkStatus(String reference);
}
// 新系统的请求/响应模型(优雅的DTO)
@Data
public class PaymentRequest {
private String customerId;
private BigDecimal amount;
private String currencyCode;
private String paymentMethod;
private Map<String, String> metadata;
}
@Data
public class PaymentResponse {
private String referenceId;
private boolean successful;
private String message;
}
public enum TransactionStatus {
PENDING, PROCESSING, COMPLETED, FAILED, REFUNDED
}
// 适配器:把老接口“翻译”成新接口(转接头核心)
@Component
public class LegacyPaymentAdapter implements ModernPaymentGateway {
private final LegacyPaymentService legacyService;
@Autowired
public LegacyPaymentAdapter(LegacyPaymentService legacyService) {
this.legacyService = legacyService;
}
@Override
public PaymentResponse pay(PaymentRequest request) {
// 第一步:把新请求参数,转换成老接口需要的参数
boolean result = legacyService.processPayment(
request.getCustomerId(), // 新的customerId = 老的accountNumber
request.getAmount().doubleValue(), // 新的BigDecimal = 老的double
request.getCurrencyCode() // 新的currencyCode = 老的currency
);
// 第二步:把老接口的返回值,转换成新接口的返回值
PaymentResponse response = new PaymentResponse();
response.setSuccessful(result);
response.setReferenceId(UUID.randomUUID().toString());
response.setMessage(result ? "支付成功~" : "支付失败,再试试!");
return response;
}
@Override
public TransactionStatus checkStatus(String reference) {
// 把老接口的状态字符串,转换成新接口的枚举
String status = legacyService.getTransactionStatus(reference);
switch (status) {
case "COMPLETED":
return TransactionStatus.COMPLETED;
case "FAILED":
return TransactionStatus.FAILED;
case "IN_PROGRESS":
return TransactionStatus.PROCESSING;
default:
return TransactionStatus.PENDING;
}
}
}
// 新系统的 checkout 服务(只用新接口,不知道老系统的存在)
@Service
public class CheckoutService {
private final ModernPaymentGateway paymentGateway;
@Autowired
public CheckoutService(ModernPaymentGateway paymentGateway) {
this.paymentGateway = paymentGateway;
}
public void processCheckout(Cart cart, String customerId) {
// 用新接口的请求模型,组装参数
PaymentRequest request = new PaymentRequest();
request.setCustomerId(customerId);
request.setAmount(cart.getTotal());
request.setCurrencyCode("USD");
// 调用新接口(底层其实是老系统在干活,但是新系统不知道)
PaymentResponse response = paymentGateway.pay(request);
if (response.isSuccessful()) {
// 支付成功逻辑
} else {
// 支付失败逻辑
}
}
}
实战优势
复用老代码: 不用重写祖传代码,加个适配器就能在新系统里用
平滑过渡: 新旧系统并行运行,慢慢迁移,不影响业务
解耦: 新系统不用关心老接口的细节,只管调用新接口
7. 装饰器模式(Decorator Pattern)
模式概述
“对象的穿衣大师”:动态给对象加 “新技能”,不用改原对象的代码 —— 相当于给手机贴钢化膜(加保护)、装手机壳(加颜值),手机本身没变,但多了新功能。
SpringBoot 实战场景
SpringBoot 的@Cacheable、@Transactional注解,全是它的杰作!比如一个普通的查询方法,加个@Cacheable,就多了 “缓存” 功能;加个@Transactional,就多了 “事务” 功能 —— 原方法代码一点没改。
代码示例(通知服务增强)
// 基础接口:通知服务(核心功能:发通知)
public interface NotificationService {
void send(String message, String recipient);
}
// 基础实现:邮件通知(核心功能的实现)
@Service
@Primary
public class EmailNotificationService implements NotificationService {
@Override
public void send(String message, String recipient) {
System.out.println("给[" + recipient + "]发邮件:" + message);
// 实际发邮件的逻辑
}
}
// 装饰器基类:所有装饰器都要继承它(相当于“衣服的基础款”)
public abstract class NotificationDecorator implements NotificationService {
protected NotificationService wrapped; // 被装饰的对象(比如EmailNotificationService)
public NotificationDecorator(NotificationService wrapped) {
this.wrapped = wrapped;
}
}
// 装饰器1:日志装饰器(给通知加“日志记录”技能)
@Component
public class LoggingNotificationDecorator extends NotificationDecorator {
private final Logger logger = LoggerFactory.getLogger(LoggingNotificationDecorator.class);
public LoggingNotificationDecorator(NotificationService wrapped) {
super(wrapped);
}
@Override
public void send(String message, String recipient) {
logger.info("准备给[" + recipient + "]发通知啦~");
long startTime = System.currentTimeMillis();
wrapped.send(message, recipient); // 调用被装饰对象的核心功能
long endTime = System.currentTimeMillis();
logger.info("给[" + recipient + "]发通知完成,耗时[" + (endTime - startTime) + "]ms");
}
}
// 装饰器2:重试装饰器(给通知加“失败重试”技能)
@Component
public class RetryNotificationDecorator extends NotificationDecorator {
private final Logger logger = LoggerFactory.getLogger(RetryNotificationDecorator.class);
private final int maxRetries; // 最大重试次数(从配置文件读取)
public RetryNotificationDecorator(
@Qualifier("loggingNotificationDecorator") NotificationService wrapped,
@Value("${notification.max-retries:3}") int maxRetries) {
super(wrapped);
this.maxRetries = maxRetries;
}
@Override
public void send(String message, String recipient) {
int attempts = 0;
boolean sent = false;
while (!sent && attempts < maxRetries) {
try {
attempts++;
wrapped.send(message, recipient); // 调用上一个装饰器的功能(日志+核心)
sent = true;
} catch (Exception e) {
logger.warn("第[" + attempts + "]次发通知失败:" + e.getMessage());
if (attempts >= maxRetries) {
logger.error("重试次数用完了,发通知彻底失败!");
throw e;
}
// 指数退避:重试间隔越来越长(100ms、200ms、400ms...)
try {
Thread.sleep((long) Math.pow(2, attempts) * 100);
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
}
}
}
}
}
// 装饰器3:加密装饰器(给通知加“消息加密”技能)
@Component
public class EncryptionNotificationDecorator extends NotificationDecorator {
public EncryptionNotificationDecorator(
@Qualifier("retryNotificationDecorator") NotificationService wrapped) {
super(wrapped);
}
@Override
public void send(String message, String recipient) {
String encryptedMessage = encrypt(message); // 加密消息
wrapped.send(encryptedMessage, recipient); // 调用上一个装饰器的功能(重试+日志+核心)
}
private String encrypt(String message) {
// 简单加密逻辑(实际项目用更安全的加密方式)
return "ENCRYPTED[" + message + "]";
}
}
// 装饰器配置:把装饰器链起来(加密→重试→日志→核心)
@Configuration
public class NotificationConfig {
@Bean
public NotificationService loggingNotificationDecorator(
@Qualifier("emailNotificationService") NotificationService emailService) {
return new LoggingNotificationDecorator(emailService);
}
@Bean
public NotificationService retryNotificationDecorator(
@Qualifier("loggingNotificationDecorator") NotificationService loggingDecorator,
@Value("${notification.max-retries:3}") int maxRetries) {
return new RetryNotificationDecorator(loggingDecorator, maxRetries);
}
@Bean
public NotificationService encryptionNotificationDecorator(
@Qualifier("retryNotificationDecorator") NotificationService retryDecorator) {
return new EncryptionNotificationDecorator(retryDecorator);
}
// 最终的Bean:装饰器链的最外层(加密装饰器)
@Bean
@Primary
public NotificationService notificationService(
@Qualifier("encryptionNotificationDecorator") NotificationService encryptionDecorator) {
return encryptionDecorator;
}
}
// 使用装饰后的服务(注入的是装饰器链,拥有所有技能)
@Service
public class UserService {
private final NotificationService notificationService;
@Autowired
public UserService(NotificationService notificationService) {
this.notificationService = notificationService;
}
public void notifyUser(User user, String message) {
// 一次调用,触发所有装饰器功能:加密→重试→日志→发邮件
notificationService.send(message, user.getEmail());
}
}
实战优势
动态增强: 不用改原代码,就能给对象加新功能(符合 “开闭原则”)
组合灵活: 多个装饰器可以自由组合(比如有的场景需要 “日志 + 重试”,有的需要 “加密 + 日志”)
接口一致: 装饰后的对象和原对象接口一样,调用方不用改代码
8. 观察者模式(Observer Pattern)
模式概述
“消息广播员”:定义一对多的关系,当一个对象(广播员)状态变化时,所有依赖它的对象(听众)都会收到通知,自动更新 —— 相当于公众号发推文,所有关注的人都会收到消息。
SpringBoot 实战场景
SpringBoot 的事件机制(ApplicationEvent、ApplicationListener)就是它的实现!比如用户注册成功后,要发欢迎邮件、创建用户档案、添加营销订阅,这些操作都可以作为 “听众”,监听 “用户注册” 这个事件。
代码示例(用户注册事件)
// 自定义事件:用户注册事件(相当于“推文”)
public class UserRegisteredEvent extends ApplicationEvent {
private final User user; // 事件携带的信息(注册的用户)
public UserRegisteredEvent(Object source, User user) {
super(source);
this.user = user;
}
public User getUser() {
return user;
}
}
// 事件发布者:用户注册服务(相当于“公众号”)
@Service
public class UserRegistrationService {
private final ApplicationEventPublisher eventPublisher; // Spring提供的事件发布器
private final UserRepository userRepository;
@Autowired
public UserRegistrationService(
ApplicationEventPublisher eventPublisher,
UserRepository userRepository) {
this.eventPublisher = eventPublisher;
this.userRepository = userRepository;
}
@Transactional
public User registerUser(UserRegistrationDto registrationDto) {
// 1. 创建并保存用户(核心业务)
User user = new User();
user.setUsername(registrationDto.getUsername());
user.setEmail(registrationDto.getEmail());
user.setPassword(encodePassword(registrationDto.getPassword()));
user.setRegistrationDate(LocalDateTime.now());
User savedUser = userRepository.save(user);
// 2. 发布“用户注册成功”事件(发推文)
eventPublisher.publishEvent(new UserRegisteredEvent(this, savedUser));
return savedUser;
}
private String encodePassword(String password) {
// 密码加密逻辑(比如BCrypt)
return "{bcrypt}" + password;
}
}
// 事件监听器1:发送欢迎邮件(听众1)
@Component
public class WelcomeEmailListener implements ApplicationListener<UserRegisteredEvent> {
private final EmailService emailService;
@Autowired
public WelcomeEmailListener(EmailService emailService) {
this.emailService = emailService;
}
@Override
public void onApplicationEvent(UserRegisteredEvent event) {
User user = event.getUser();
// 收到事件,执行发送欢迎邮件
emailService.sendWelcomeEmail(user);
}
}
// 事件监听器2:创建用户档案(听众2)
@Component
public class UserProfileInitializer implements ApplicationListener<UserRegisteredEvent> {
private final ProfileService profileService;
@Autowired
public UserProfileInitializer(ProfileService profileService) {
this.profileService = profileService;
}
@Override
public void onApplicationEvent(UserRegisteredEvent event) {
User user = event.getUser();
// 收到事件,执行创建用户档案
profileService.createInitialProfile(user);
}
}
// 事件监听器3:添加营销订阅(听众3,用注解方式,更简洁)
@Component
public class MarketingSubscriptionHandler {
private final MarketingService marketingService;
@Autowired
public MarketingSubscriptionHandler(MarketingService marketingService) {
this.marketingService = marketingService;
}
// @EventListener:标记为事件监听器,监听UserRegisteredEvent
// @Async:异步执行,不阻塞主线程
@EventListener
@Async
public void handleUserRegistered(UserRegisteredEvent event) {
User user = event.getUser();
// 收到事件,执行添加营销订阅
marketingService.addUserToDefaultNewsletters(user);
}
}
// 配置异步事件:让@Async生效(异步执行监听器,提高性能)
@Configuration
@EnableAsync
public class AsyncConfig implements AsyncConfigurer {
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5); // 核心线程数
executor.setMaxPoolSize(10); // 最大线程数
executor.setQueueCapacity(25); // 队列容量
executor.setThreadNamePrefix("EventHandler-"); // 线程名前缀(方便排查问题)
executor.initialize();
return executor;
}
}
实战优势
解耦: 发布者不用知道有哪些听众,只管发布事件;听众不用知道发布者的细节,只管监听事件
异步处理: 支持异步执行监听器,不会阻塞主线程(比如添加营销订阅比较耗时,异步执行不影响用户注册的响应速度)
易扩展: 新增一个操作(比如注册后送积分),只需要加一个监听器,不用改发布者的代码
9. 策略模式(Strategy Pattern)
模式概述
“算法切换大师”:定义一组算法,把每个算法都封装起来,让它们可以互相替换 —— 相当于手机的 “拍照模式”,普通模式、夜景模式、人像模式,按需切换,核心都是 “拍照”。
SpringBoot 实战场景
SpringBoot 的缓存策略、认证策略,全是它的应用!比如电商的折扣策略:新用户折扣、会员折扣、大额订单折扣,不同用户 / 订单用不同的折扣算法,随时可以切换。
代码示例(折扣策略)
// 折扣策略接口:定义“折扣算法”的规范
public interface DiscountStrategy {
BigDecimal applyDiscount(BigDecimal amount, User user); // 计算折扣后金额
boolean isApplicable(User user, ShoppingCart cart); // 判断该策略是否适用
}
// 策略1:新用户折扣(注册30天内的用户)
@Component
public class NewUserDiscountStrategy implements DiscountStrategy {
@Value("${discount.new-user.percentage:10}")
private int discountPercentage; // 折扣比例(从配置文件读取,默认10%)
@Override
public BigDecimal applyDiscount(BigDecimal amount, User user) {
BigDecimal discountFactor = BigDecimal.valueOf(discountPercentage)
.divide(BigDecimal.valueOf(100));
BigDecimal discount = amount.multiply(discountFactor);
return amount.subtract(discount); // 原价 - 折扣 = 折后价
}
@Override
public boolean isApplicable(User user, ShoppingCart cart) {
LocalDateTime thirtyDaysAgo = LocalDateTime.now().minusDays(30);
return user.getRegistrationDate().isAfter(thirtyDaysAgo); // 注册时间在30天内
}
}
// 策略2:会员折扣(VIP会员)
@Component
public class PremiumMemberDiscountStrategy implements DiscountStrategy {
@Value("${discount.premium-member.percentage:15}")
private int discountPercentage; // 会员折扣比例(默认15%)
@Override
public BigDecimal applyDiscount(BigDecimal amount, User user) {
BigDecimal discountFactor = BigDecimal.valueOf(discountPercentage)
.divide(BigDecimal.valueOf(100));
BigDecimal discount = amount.multiply(discountFactor);
return amount.subtract(discount);
}
@Override
public boolean isApplicable(User user, ShoppingCart cart) {
return "PREMIUM".equals(user.getMembershipLevel()); // 会员等级是PREMIUM
}
}
// 策略3:大额订单折扣(订单金额超过阈值)
@Component
public class LargeOrderDiscountStrategy implements DiscountStrategy {
@Value("${discount.large-order.threshold:1000}")
private BigDecimal threshold; // 大额订单阈值(默认1000元)
@Value("${discount.large-order.percentage:5}")
private int discountPercentage; // 大额订单折扣比例(默认5%)
@Override
public BigDecimal applyDiscount(BigDecimal amount, User user) {
BigDecimal discountFactor = BigDecimal.valueOf(discountPercentage)
.divide(BigDecimal.valueOf(100));
BigDecimal discount = amount.multiply(discountFactor);
return amount.subtract(discount);
}
@Override
public boolean isApplicable(User user, ShoppingCart cart) {
return cart.getTotalAmount().compareTo(threshold) >= 0; // 订单金额>=阈值
}
}
// 策略上下文:折扣服务(负责选择合适的策略)
@Service
public class DiscountService {
private final List<DiscountStrategy> discountStrategies; // 自动注入所有折扣策略
@Autowired
public DiscountService(List<DiscountStrategy> discountStrategies) {
this.discountStrategies = discountStrategies;
}
// 计算最优折扣(选择折扣最大的策略)
public BigDecimal calculateDiscountedAmount(BigDecimal originalAmount, User user, ShoppingCart cart) {
DiscountStrategy bestStrategy = findBestDiscountStrategy(user, cart);
if (bestStrategy != null) {
return bestStrategy.applyDiscount(originalAmount, user);
}
return originalAmount; // 没有适用的策略,返回原价
}
// 查找最优策略(遍历所有策略,选折扣最大的)
private DiscountStrategy findBestDiscountStrategy(User user, ShoppingCart cart) {
BigDecimal originalAmount = cart.getTotalAmount();
BigDecimal bestDiscount = BigDecimal.ZERO;
DiscountStrategy bestStrategy = null;
for (DiscountStrategy strategy : discountStrategies) {
if (strategy.isApplicable(user, cart)) { // 先判断策略是否适用
BigDecimal discountedAmount = strategy.applyDiscount(originalAmount, user);
BigDecimal discount = originalAmount.subtract(discountedAmount); // 计算折扣金额
if (discount.compareTo(bestDiscount) > 0) { // 找到更大的折扣
bestDiscount = discount;
bestStrategy = strategy;
}
}
}
return bestStrategy;
}
}
实战优势
算法独立: 每个算法都封装成单独的类,方便维护和修改
动态切换: 可以根据不同的场景,动态选择不同的算法(比如新用户自动用新用户折扣)
消除 if-else: 不用写一堆if (是新用户) { … } else if (是会员) { … }的代码
易扩展: 新增折扣策略(比如节日折扣),只需要加一个策略类,不用改旧代码
10. 模板方法模式(Template Method Pattern)
模式概述
“算法骨架师”:定义一个算法的骨架(步骤),把一些可变的步骤推迟到子类里实现 —— 相当于做蛋糕的食谱:步骤是固定的(准备材料→混合→烘烤→装饰),但装饰步骤可以自己发挥(抹奶油、放水果)。
SpringBoot 实战场景
SpringBoot 的JdbcTemplate、RestTemplate,全是它的经典实现!比如JdbcTemplate的查询流程(获取连接→创建 Statement→执行查询→处理结果→关闭连接)是固定的,处理结果的步骤(比如把 ResultSet 转换成对象)留给用户自己实现。
代码示例(报表导出场景)
// 抽象模板类:报表导出器(定义导出报表的固定步骤)
@Component
public abstract class AbstractReportExporter {
// 模板方法:定义导出报表的算法骨架(固定步骤,子类不能改)
public final void exportReport(ReportRequest request, OutputStream output) {
try {
// 步骤1:校验请求(固定)
validateRequest(request);
// 步骤2:获取数据(固定)
ReportData data = fetchData(request);
// 步骤3:处理数据(固定,子类可以重写)
ReportData processedData = processData(data);
// 步骤4:格式化数据(可变,子类必须实现)
byte[] formattedData = formatData(processedData);
// 步骤5:写入输出流(固定)
output.write(formattedData);
output.flush();
// 步骤6:记录日志(固定)
logExport(request, processedData);
} catch (Exception e) {
// 步骤7:处理异常(固定)
handleExportError(e, request);
}
}
// 固定方法:校验请求(子类不用管)
protected void validateRequest(ReportRequest request) {
if (request == null) {
throw new IllegalArgumentException("报表请求不能为null!");
}
if (request.getStartDate() == null || request.getEndDate() == null) {
throw new IllegalArgumentException("开始日期和结束日期是必填项!");
}
if (request.getStartDate().isAfter(request.getEndDate())) {
throw new IllegalArgumentException("开始日期不能晚于结束日期!");
}
}
// 抽象方法:获取数据(子类必须实现,因为不同报表的数据来源不同)
protected abstract ReportData fetchData(ReportRequest request);
// 钩子方法:处理数据(子类可以选择重写,默认不处理)
protected ReportData processData(ReportData data) {
return data; // 默认不处理,直接返回原数据
}
// 抽象方法:格式化数据(子类必须实现,因为不同格式的报表(PDF/Excel)格式化方式不同)
protected abstract byte[] formatData(ReportData data) throws IOException;
// 固定方法:记录日志(子类不用管)
protected void logExport(ReportRequest request, ReportData data) {
System.out.println("报表导出成功!时间范围:" +
request.getStartDate() + " 到 " + request.getEndDate() +
",记录数:" + data.getRecords().size());
}
// 固定方法:处理异常(子类不用管)
protected void handleExportError(Exception e, ReportRequest request) {
System.err.println("报表导出失败:" + e.getMessage());
throw new ReportExportException("报表导出失败,请重试!", e);
}
}
// 具体模板1:PDF报表导出器(实现抽象方法,处理PDF格式)
@Component("pdfExporter")
public class PdfReportExporter extends AbstractReportExporter {
@Autowired
private ReportRepository reportRepository;
@Override
protected ReportData fetchData(ReportRequest request) {
// PDF报表的数据来源(从数据库查询)
List<ReportRecord> records = reportRepository.findByDateRange(
request.getStartDate(), request.getEndDate());
return new ReportData(records, request.getStartDate(), request.getEndDate());
}
@Override
protected ReportData processData(ReportData data) {
// 重写钩子方法:对数据进行排序处理(PDF报表需要排序)
List<ReportRecord> processedRecords = data.getRecords().stream()
.sorted(Comparator.comparing(ReportRecord::getDate))
.collect(Collectors.toList());
return new ReportData(processedRecords, data.getStartDate(), data.getEndDate());
}
@Override
protected byte[] formatData(ReportData data) throws IOException {
// 实现PDF格式化逻辑(用iText库)
Document document = new Document();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
PdfWriter.getInstance(document, baos);
document.open();
// 添加报表标题
document.add(new Paragraph("报表(" + data.getStartDate() + " 到 " + data.getEndDate() + ")"));
// 创建PDF表格(3列:日期、描述、金额)
PdfPTable table = new PdfPTable(3);
table.addCell("日期");
table.addCell("描述");
table.addCell("金额");
// 填充数据
for (ReportRecord record : data.getRecords()) {
table.addCell(record.getDate().toString());
table.addCell(record.getDescription());
table.addCell(record.getAmount().toString());
}
document.add(table);
} finally {
if (document.isOpen()) {
document.close();
}
}
return baos.toByteArray();
}
}
// 具体模板2:Excel报表导出器(实现抽象方法,处理Excel格式)
@Component("excelExporter")
public class ExcelReportExporter extends AbstractReportExporter {
@Autowired
private ReportRepository reportRepository;
@Override
protected ReportData fetchData(ReportRequest request) {
// Excel报表的数据来源(和PDF一样,从数据库查询)
List<ReportRecord> records = reportRepository.findByDateRange(
request.getStartDate(), request.getEndDate());
return new ReportData(records, request.getStartDate(), request.getEndDate());
}
// 不重写processData方法,使用父类的默认实现(Excel报表不需要额外处理数据)
@Override
protected byte[] formatData(ReportData data) throws IOException {
// 实现Excel格式化逻辑(用POI库)
Workbook workbook = new XSSFWorkbook();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
Sheet sheet = workbook.createSheet("报表数据");
// 创建表头行
Row headerRow = sheet.createRow(0);
headerRow.createCell(0).setCellValue("日期");
headerRow.createCell(1).setCellValue("描述");
headerRow.createCell(2).setCellValue("金额");
// 填充数据行
int rowNum = 1;
for (ReportRecord record : data.getRecords()) {
Row row = sheet.createRow(rowNum++);
row.createCell(0).setCellValue(record.getDate().toString());
row.createCell(1).setCellValue(record.getDescription());
row.createCell(2).setCellValue(record.getAmount().doubleValue());
}
// 自动调整列宽
for (int i = 0; i < 3; i++) {
sheet.autoSizeColumn(i);
}
workbook.write(baos);
} finally {
workbook.close();
}
return baos.toByteArray();
}
}
// 控制器:使用模板方法导出报表
@RestController
@RequestMapping("/reports")
public class ReportController {
@Autowired
@Qualifier("pdfExporter")
private AbstractReportExporter pdfExporter;
@Autowired
@Qualifier("excelExporter")
private AbstractReportExporter excelExporter;
// 导出PDF报表
@GetMapping(value = "/export/pdf", produces = MediaType.APPLICATION_PDF_VALUE)
public void exportPdf(
@RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate startDate,
@RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate endDate,
HttpServletResponse response) throws IOException {
response.setHeader("Content-Disposition", "attachment; filename=report.pdf");
ReportRequest request = new ReportRequest();
request.setStartDate(startDate);
request.setEndDate(endDate);
pdfExporter.exportReport(request, response.getOutputStream());
}
// 导出Excel报表
@GetMapping(value = "/export/excel",
produces = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
public void exportExcel(
@RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate startDate,
@RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate endDate,
HttpServletResponse response) throws IOException {
response.setHeader("Content-Disposition", "attachment; filename=report.xlsx");
ReportRequest request = new ReportRequest();
request.setStartDate(startDate);
request.setEndDate(endDate);
excelExporter.exportReport(request, response.getOutputStream());
}
}
实战优势
代码复用: 把固定的步骤(校验、日志、异常处理)提取到父类,子类只关注可变的步骤
控制扩展: 父类定义算法骨架,子类只能在指定的扩展点(抽象方法、钩子方法)修改,不会破坏算法结构
符合 “开闭原则”: 新增报表格式(比如 Word),只需要加一个子类,不用改父类的代码
11. 责任链模式(Chain of Responsibility Pattern)
模式概述
“请求接力赛”:把多个处理器组成一条链,请求从链的开头出发,依次经过每个处理器,直到有一个处理器能处理它 —— 相当于公司请假流程:员工→组长→部门经理→总经理,每个层级判断自己能不能批,不能批就交给下一级。
SpringBoot 实战场景
SpringBoot 的 Filter 链、Interceptor 链,全是它的实现!比如一个 HTTP 请求,会经过多个 Filter(登录校验 Filter、权限校验 Filter、日志 Filter),每个 Filter 处理完,再交给下一个 Filter,直到交给 DispatcherServlet。
代码示例(支付流程处理)
// 抽象处理器:支付处理器(定义处理请求的方法和下一个处理器)
public abstract class PaymentHandler {
protected PaymentHandler nextHandler; // 下一个处理器(接力的人)
// 设置下一个处理器(组装责任链)
public void setNext(PaymentHandler handler) {
this.nextHandler = handler;
}
// 处理支付请求(子类必须实现)
public abstract PaymentResponse handle(PaymentRequest request);
}
// 处理器1:参数校验处理器(第一个接力的人,负责校验参数)
@Component
public class ValidationHandler extends PaymentHandler {
@Override
public PaymentResponse handle(PaymentRequest request) {
// 校验支付金额
if (request.getAmount().compareTo(BigDecimal.ZERO) <= 0) {
return new PaymentResponse(false, "支付金额必须大于0!");
}
// 校验卡号
if (request.getCardNumber() == null || request.getCardNumber().isEmpty()) {
return new PaymentResponse(false, "银行卡号不能为空!");
}
// 校验卡号长度(13-19位)
if (request.getCardNumber().length() < 13 || request.getCardNumber().length() > 19) {
return new PaymentResponse(false, "银行卡号长度无效!");
}
// 校验有效期
if (request.getExpiryDate() == null) {
return new PaymentResponse(false, "银行卡有效期不能为空!");
}
if (request.getExpiryDate().isBefore(YearMonth.now())) {
return new PaymentResponse(false, "银行卡已过期!");
}
// 校验通过,交给下一个处理器
if (nextHandler != null) {
return nextHandler.handle(request);
}
return new PaymentResponse(true, "参数校验通过!");
}
}
// 处理器2:风控处理器(第二个接力的人,负责检测欺诈)
@Component
public class FraudDetectionHandler extends PaymentHandler {
@Autowired
private FraudDetectionService fraudService; // 风控服务
@Override
public PaymentResponse handle(PaymentRequest request) {
// 调用风控服务,检测是否有欺诈风险
FraudCheckResult checkResult = fraudService.checkForFraud(
request.getCardNumber(),
request.getAmount(),
request.getIpAddress());
if (checkResult.isFraudulent()) {
return new PaymentResponse(false, "交易存在欺诈风险:" + checkResult.getReason());
}
// 风控通过,交给下一个处理器
if (nextHandler != null) {
return nextHandler.handle(request);
}
return new PaymentResponse(true, "风控检测通过!");
}
}
// 处理器3:支付处理处理器(第三个接力的人,负责实际支付)
@Component
public class PaymentProcessingHandler extends PaymentHandler {
@Autowired
private PaymentGateway paymentGateway; // 支付网关(调用第三方支付接口)
@Override
public PaymentResponse handle(PaymentRequest request) {
// 调用支付网关,执行实际支付
PaymentGatewayResponse gatewayResponse = paymentGateway.processPayment(
request.getCardNumber(),
request.getExpiryDate(),
request.getCvv(),
request.getAmount());
if (!gatewayResponse.isSuccessful()) {
return new PaymentResponse(false, "支付失败:" + gatewayResponse.getMessage());
}
// 支付成功,交给下一个处理器
if (nextHandler != null) {
PaymentResponse nextResponse = nextHandler.handle(request);
// 如果下一个步骤失败(比如通知失败),需要退款
if (!nextResponse.isSuccess()) {
paymentGateway.refund(gatewayResponse.getTransactionId(), request.getAmount());
return nextResponse;
}
// 把支付网关返回的交易ID添加到响应中
nextResponse.setTransactionId(gatewayResponse.getTransactionId());
return nextResponse;
}
return new PaymentResponse(true, "支付处理成功!", gatewayResponse.getTransactionId());
}
}
// 处理器4:通知处理器(第四个接力的人,负责支付结果通知)
@Component
public class NotificationHandler extends PaymentHandler {
@Autowired
private NotificationService notificationService; // 通知服务(短信/邮件通知)
@Override
public PaymentResponse handle(PaymentRequest request) {
// 调用通知服务,给用户发送支付成功通知
notificationService.sendPaymentConfirmation(
request.getEmail(),
request.getAmount(),
LocalDateTime.now());
// 通知发送完成,交给下一个处理器(如果有的话)
if (nextHandler != null) {
return nextHandler.handle(request);
}
return new PaymentResponse(true, "支付完成且通知已发送!");
}
}
// 责任链配置:组装处理器链条
@Configuration
public class PaymentHandlerConfig {
@Bean
public PaymentHandler paymentHandlerChain(
ValidationHandler validationHandler,
FraudDetectionHandler fraudDetectionHandler,
PaymentProcessingHandler paymentProcessingHandler,
NotificationHandler notificationHandler) {
// 构建责任链:参数校验 → 风控检测 → 支付处理 → 结果通知
validationHandler.setNext(fraudDetectionHandler);
fraudDetectionHandler.setNext(paymentProcessingHandler);
paymentProcessingHandler.setNext(notificationHandler);
// 返回链条的第一个处理器(入口)
return validationHandler;
}
}
// 支付服务:触发责任链处理
@Service
public class PaymentService {
private final PaymentHandler paymentHandlerChain; // 注入组装好的责任链
@Autowired
public PaymentService(PaymentHandler paymentHandlerChain) {
this.paymentHandlerChain = paymentHandlerChain;
}
public PaymentResponse processPayment(PaymentRequest request) {
// 从责任链入口开始处理支付请求
return paymentHandlerChain.handle(request);
}
}
实战优势
解耦请求方与处理方: 支付服务只需要调用责任链入口,不用知道具体有哪些处理器、每个处理器做什么。
灵活调整流程: 新增 / 移除处理器(比如加 “优惠券抵扣处理器”),只需改配置,不用改业务代码;调整处理器顺序也很方便。
单一职责: 每个处理器只做一件事(校验 / 风控 / 支付 / 通知),代码清晰、易维护。
扩展性强: 后续要加新的处理步骤,直接写新的处理器类,接入链条即可,完全符合 “开闭原则”。
12. 命令模式(Command Pattern)
模式概述
“请求封装大师”:把一个请求(比如 “创建订单”“扣减库存”)封装成一个对象,将 “发请求的人” 和 “处理请求的人” 解耦 —— 相当于餐厅里的菜单:顾客(请求方)只需要点菜单(命令对象),厨师(处理方)按菜单做菜,双方不用直接沟通。
SpringBoot 实战场景
SpringBoot 的事件处理、任务调度、事务回滚都常用它!比如订单下单流程:创建订单、扣减库存、处理支付,每个步骤封装成一个命令,既能按顺序执行,也能在出错时反向撤销(比如支付失败,就撤销 “扣减库存” 和 “创建订单”)。
代码示例(订单下单流程)
// 命令接口:定义执行和撤销行为
public interface Command {
void execute(); // 执行命令
void undo(); // 撤销命令
String getDescription(); // 获取命令描述(日志用)
}
// 具体命令1:创建订单命令
@Component
public class CreateOrderCommand implements Command {
private final OrderService orderService;
private final OrderRepository orderRepository;
private Order createdOrder; // 保存执行结果,用于撤销
private final Order orderToCreate; // 要创建的订单数据
// 通过构造器注入依赖和订单数据
public CreateOrderCommand(
OrderService orderService,
OrderRepository orderRepository,
Order orderToCreate) {
this.orderService = orderService;
this.orderRepository = orderRepository;
this.orderToCreate = orderToCreate;
}
@Override
public void execute() {
// 执行“创建订单”逻辑
createdOrder = orderService.createOrder(orderToCreate);
}
@Override
public void undo() {
// 撤销“创建订单”:删除已创建的订单
if (createdOrder != null) {
orderRepository.delete(createdOrder);
createdOrder = null;
}
}
@Override
public String getDescription() {
return "创建订单(客户ID:" + orderToCreate.getCustomerId() + ")";
}
}
// 具体命令2:扣减库存命令
@Component
public class DeductInventoryCommand implements Command {
private final InventoryService inventoryService;
private final Long productId; // 商品ID
private final int quantity; // 扣减数量
private boolean executed = false; // 标记是否已执行,避免重复撤销
public DeductInventoryCommand(
InventoryService inventoryService,
Long productId,
int quantity) {
this.inventoryService = inventoryService;
this.productId = productId;
this.quantity = quantity;
}
@Override
public void execute() {
// 执行“扣减库存”逻辑
inventoryService.deductStock(productId, quantity);
executed = true;
}
@Override
public void undo() {
// 撤销“扣减库存”:把库存加回去
if (executed) {
inventoryService.addStock(productId, quantity);
executed = false;
}
}
@Override
public String getDescription() {
return "扣减库存(商品ID:" + productId + ",数量:" + quantity + ")";
}
}
// 具体命令3:处理支付命令
@Component
public class ProcessPaymentCommand implements Command {
private final PaymentService paymentService;
private final PaymentRequest paymentRequest; // 支付请求数据
private String transactionId; // 保存支付交易ID,用于撤销(退款)
public ProcessPaymentCommand(
PaymentService paymentService,
PaymentRequest paymentRequest) {
this.paymentService = paymentService;
this.paymentRequest = paymentRequest;
}
@Override
public void execute() {
// 执行“处理支付”逻辑
PaymentResponse response = paymentService.processPayment(paymentRequest);
if (!response.isSuccess()) {
throw new PaymentFailedException("支付失败:" + response.getMessage());
}
transactionId = response.getTransactionId();
}
@Override
public void undo() {
// 撤销“处理支付”:发起退款
if (transactionId != null) {
paymentService.refundPayment(transactionId);
transactionId = null;
}
}
@Override
public String getDescription() {
return "处理支付(订单ID:" + paymentRequest.getOrderId() + ",金额:" + paymentRequest.getAmount() + ")";
}
}
// 命令历史:记录已执行的命令(用于撤销)
@Component
public class CommandHistory {
// 用双端队列保存命令,支持先进后出(撤销时从最后一个命令开始)
private final Deque<Command> history = new ArrayDeque<>();
public void push(Command command) {
history.push(command);
}
public Command pop() {
return history.isEmpty() ? null : history.pop();
}
public boolean isEmpty() {
return history.isEmpty();
}
public List<Command> getExecutedCommands() {
return new ArrayList<>(history);
}
}
// 命令调用器:负责执行命令和处理撤销(核心调度)
@Service
public class CommandInvoker {
private final CommandHistory history;
private final TransactionTemplate transactionTemplate; // 事务模板,保证命令执行的原子性
@Autowired
public CommandInvoker(
CommandHistory history,
PlatformTransactionManager transactionManager) {
this.history = history;
this.transactionTemplate = new TransactionTemplate(transactionManager);
}
// 执行单个命令(带事务)
public void executeCommand(Command command) {
transactionTemplate.execute(status -> {
try {
command.execute();
history.push(command); // 执行成功,记录到历史
return null;
} catch (Exception e) {
status.setRollbackOnly(); // 执行失败,回滚事务
throw e;
}
});
}
// 批量执行命令(按顺序执行,出错则批量撤销)
public void executeCommands(List<Command> commands) {
transactionTemplate.execute(status -> {
List<Command> executedCommands = new ArrayList<>();
try {
// 按顺序执行每个命令
for (Command command : commands) {
command.execute();
executedCommands.add(command);
}
// 所有命令执行成功,批量记录到历史
executedCommands.forEach(history::push);
return null;
} catch (Exception e) {
// 执行失败,反向撤销已执行的命令(比如先撤销“支付”,再撤销“扣库存”,最后撤销“创建订单”)
Collections.reverse(executedCommands);
executedCommands.forEach(Command::undo);
status.setRollbackOnly();
throw e;
}
});
}
// 撤销最后一个执行的命令
public void undoLastCommand() {
Command command = history.pop();
if (command != null) {
transactionTemplate.execute(status -> {
try {
command.undo();
return null;
} catch (Exception e) {
status.setRollbackOnly();
history.push(command); // 撤销失败,把命令放回历史
throw e;
}
});
}
}
}
// 订单处理服务:组装命令并触发执行
@Service
public class OrderProcessingService {
private final CommandInvoker commandInvoker;
private final OrderService orderService;
private final InventoryService inventoryService;
private final PaymentService paymentService;
@Autowired
public OrderProcessingService(
CommandInvoker commandInvoker,
OrderService orderService,
InventoryService inventoryService,
PaymentService paymentService) {
this.commandInvoker = commandInvoker;
this.orderService = orderService;
this.inventoryService = inventoryService;
this.paymentService = paymentService;
}
public Order placeOrder(OrderRequest orderRequest) {
// 1. 组装订单数据
Order order = new Order();
order.setCustomerId(orderRequest.getCustomerId());
order.setItems(orderRequest.getItems());
order.setTotalAmount(calculateTotal(orderRequest.getItems()));
// 2. 组装支付请求数据
PaymentRequest paymentRequest = new PaymentRequest();
paymentRequest.setAmount(order.getTotalAmount());
paymentRequest.setCardNumber(orderRequest.getPaymentDetails().getCardNumber());
paymentRequest.setExpiryDate(orderRequest.getPaymentDetails().getExpiryDate());
paymentRequest.setCvv(orderRequest.getPaymentDetails().getCvv());
paymentRequest.setOrderId(order.getId()); // 关联订单ID
// 3. 组装命令列表(按执行顺序)
List<Command> commands = new ArrayList<>();
// 命令1:创建订单
commands.add(new CreateOrderCommand(orderService, orderService.getRepository(), order));
// 命令2:给每个商品扣减库存
for (OrderItem item : order.getItems()) {
commands.add(new DeductInventoryCommand(inventoryService, item.getProductId(), item.getQuantity()));
}
// 命令3:处理支付
commands.add(new ProcessPaymentCommand(paymentService, paymentRequest));
// 4. 调用命令执行器,批量执行命令
commandInvoker.executeCommands(commands);
return order;
}
// 计算订单总金额
private BigDecimal calculateTotal(List<OrderItem> items) {
return items.stream()
.map(item -> item.getPrice().multiply(BigDecimal.valueOf(item.getQuantity())))
.reduce(BigDecimal.ZERO, BigDecimal::add);
}
}
实战优势
解耦请求与执行: 下单服务只需要组装命令,不用关心每个步骤怎么执行;执行逻辑封装在命令里,修改时互不影响。
支持撤销 / 重做: 每个命令都有undo方法,出错时能按顺序撤销,保证数据一致性(比如支付失败,自动回滚库存和订单)。
组合复杂操作: 把多个简单命令组合成复杂流程(如下单 = 创建订单 + 扣库存 + 支付),代码清晰且易扩展。
方便日志与监控: 通过CommandHistory能记录所有执行过的命令,便于排查问题和做审计日志。
13. 状态模式(State Pattern)
模式概述
“对象状态管家”:让对象的行为随着内部状态的变化而变化 —— 比如订单有 “新建”“已确认”“已支付”“已发货” 等状态,每个状态下能执行的操作不同(“新建” 状态能确认,不能发货;“已支付” 状态能发货,不能取消),把每个状态的行为封装成独立类,避免一堆if-else判断。
SpringBoot 实战场景
订单状态管理、支付状态流转、工作流审批(比如请假单 “待审批”“已批准”“已驳回”)都常用它!SpringBoot 中结合@Component能把每个状态托管给容器,实现状态的灵活切换。
代码示例(订单状态流转)
// 订单状态接口:定义各状态支持的行为
public interface OrderState {
OrderState confirm(Order order); // 确认订单
OrderState pay(Order order); // 支付订单
OrderState ship(Order order); // 发货
OrderState deliver(Order order); // 确认收货
OrderState cancel(Order order); // 取消订单
OrderState refund(Order order); // 退款
String getStatus(); // 获取状态标识(如“NEW”“PAID”)
}
// 具体状态1:新建状态(NEW)
@Component
public class NewOrderState implements OrderState {
@Autowired
private ConfirmedOrderState confirmedOrderState; // 下一个状态:已确认
@Autowired
private CancelledOrderState cancelledOrderState; // 下一个状态:已取消
@Override
public OrderState confirm(Order order) {
// 执行“确认订单”逻辑:记录确认时间
order.setConfirmedAt(LocalDateTime.now());
return confirmedOrderState; // 切换到“已确认”状态
}
@Override
public OrderState pay(Order order) {
// 新建状态不能直接支付,抛异常
throw new IllegalStateException("未确认的订单无法支付!");
}
@Override
public OrderState ship(Order order) {
throw new IllegalStateException("未确认未支付的订单无法发货!");
}
@Override
public OrderState deliver(Order order) {
throw new IllegalStateException("未发货的订单无法确认收货!");
}
@Override
public OrderState cancel(Order order) {
// 执行“取消订单”逻辑:记录取消时间和原因
order.setCancelledAt(LocalDateTime.now());
order.setCancellationReason("客户在确认前取消订单");
return cancelledOrderState; // 切换到“已取消”状态
}
@Override
public OrderState refund(Order order) {
throw new IllegalStateException("未支付的订单无法退款!");
}
@Override
public String getStatus() {
return "NEW";
}
}
// 具体状态2:已确认状态(CONFIRMED)
@Component
public class ConfirmedOrderState implements OrderState {
@Autowired
private PaidOrderState paidOrderState; // 下一个状态:已支付
@Autowired
private CancelledOrderState cancelledOrderState; // 下一个状态:已取消
@Override
public OrderState confirm(Order order) {
throw new IllegalStateException("订单已确认,无需重复确认!");
}
@Override
public OrderState pay(Order order) {
// 执行“支付订单”逻辑:记录支付时间
order.setPaidAt(LocalDateTime.now());
return paidOrderState; // 切换到“已支付”状态
}
@Override
public OrderState ship(Order order) {
throw new IllegalStateException("未支付的订单无法发货!");
}
@Override
public OrderState deliver(Order order) {
throw new IllegalStateException("未发货的订单无法确认收货!");
}
@Override
public OrderState cancel(Order order) {
order.setCancelledAt(LocalDateTime.now());
order.setCancellationReason("客户在支付前取消订单");
return cancelledOrderState;
}
@Override
public OrderState refund(Order order) {
throw new IllegalStateException("未支付的订单无法退款!");
}
@Override
public String getStatus() {
return "CONFIRMED";
}
}
// 具体状态3:已支付状态(PAID)
@Component
public class PaidOrderState implements OrderState {
@Autowired
private ShippedOrderState shippedOrderState; // 下一个状态:已发货
@Autowired
private RefundedOrderState refundedOrderState; // 下一个状态:已退款
@Override
public OrderState confirm(Order order) {
throw new IllegalStateException("订单已支付,无需重复确认!");
}
@Override
public OrderState pay(Order order) {
throw new IllegalStateException("订单已支付,无需重复支付!");
}
@Override
public OrderState ship(Order order) {
// 执行“发货”逻辑:记录发货时间
order.setShippedAt(LocalDateTime.now());
return shippedOrderState; // 切换到“已发货”状态
}
@Override
public OrderState deliver(Order order) {
throw new IllegalStateException("未发货的订单无法确认收货!");
}
@Override
public OrderState cancel(Order order) {
throw new IllegalStateException("已支付的订单无法取消,请申请退款!");
}
@Override
public OrderState refund(Order order) {
// 执行“退款”逻辑:记录退款时间
order.setRefundedAt(LocalDateTime.now());
return refundedOrderState; // 切换到“已退款”状态
}
@Override
public String getStatus() {
return "PAID";
}
}
// 具体状态4:已发货状态(SHIPPED)
@Component
public class ShippedOrderState implements OrderState {
@Autowired
private DeliveredOrderState deliveredOrderState; // 下一个状态:已收货
@Override
public OrderState confirm(Order order) {
throw new IllegalStateException("订单已发货,无需重复确认!");
}
@Override
public OrderState pay(Order order) {
throw new IllegalStateException("订单已支付,无需重复支付!");
}
@Override
public OrderState ship(Order order) {
throw new IllegalStateException("订单已发货,无需重复发货!");
}
@Override
public OrderState deliver(Order order) {
// 执行“确认收货”逻辑:记录收货时间
order.setDeliveredAt(LocalDateTime.now());
return deliveredOrderState; // 切换到“已收货”状态
}
@Override
public OrderState cancel(Order order) {
throw new IllegalStateException("已发货的订单无法取消,可申请退货退款!");
}
@Override
public OrderState refund(Order order) {
throw new IllegalStateException("已发货未收货的订单,需先确认收货/退货后再退款!");
}
@Override
public String getStatus() {
return "SHIPPED";
}
}
// 具体状态5:已收货状态(DELIVERED)
@Component
public class DeliveredOrderState implements OrderState {
@Autowired
private RefundedOrderState refundedOrderState; // 下一个状态:已退款
@Override
public OrderState confirm(Order order) {
throw new IllegalStateException("订单已完成收货,无需确认!");
}
@Override
public OrderState pay(Order order) {
throw new IllegalStateException("订单已支付,无需重复支付!");
}
@Override
public OrderState ship(Order order) {
throw new IllegalStateException("订单已收货,无需发货!");
}
@Override
public OrderState deliver(Order order) {
throw new IllegalStateException("订单已完成收货,无需重复确认!");
}
@Override
public OrderState cancel(Order order) {
throw new IllegalStateException("已收货的订单无法取消,可申请售后退款!");
}
@Override
public OrderState refund(Order order) {
// 执行“售后退款”逻辑:记录退款时间
order.setRefundedAt(LocalDateTime.now());
return refundedOrderState; // 切换到“已退款”状态
}
@Override
public String getStatus() {
return "DELIVERED";
}
}
// 具体状态6:已取消状态(CANCELLED)
@Component
public class CancelledOrderState implements OrderState {
@Override
public OrderState confirm(Order order) {
throw new IllegalStateException("已取消的订单无法确认!");
}
@Override
public OrderState pay(Order order) {
throw new IllegalStateException("已取消的订单无法支付!");
}
@Override
public OrderState ship(Order order) {
throw new IllegalStateException("已取消的订单无法发货!");
}
@Override
public OrderState deliver(Order order) {
throw new IllegalStateException("已取消的订单无法确认收货!");
}
@Override
public OrderState cancel(Order order) {
throw new IllegalStateException("订单已取消,无需重复取消!");
}
@Override
public OrderState refund(Order order) {
throw new IllegalStateException("未支付的取消订单无需退款!");
}
@Override
public String getStatus() {
return "CANCELLED";
}
}
// 具体状态7:已退款状态(REFUNDED)
@Component
public class RefundedOrderState implements OrderState {
@Override
public OrderState confirm(Order order) {
throw new IllegalStateException("已退款的订单无法确认!");
}
@Override
public OrderState pay(Order order) {
throw new IllegalStateException("已退款的订单无需支付!");
}
@Override
public OrderState ship(Order order) {
throw new IllegalStateException("已退款的订单无法发货!");
}
@Override
public OrderState deliver(Order order) {
throw new IllegalStateException("已退款的订单无法确认收货!");
}
@Override
public OrderState cancel(Order order) {
throw new IllegalStateException("已退款的订单无需取消!");
}
@Override
public OrderState refund(Order order) {
throw new IllegalStateException("订单已退款,无需重复退款!");
}
@Override
public String getStatus() {
return "REFUNDED";
}
}
// 订单实体:状态上下文(持有当前状态,触发状态切换)
@Entity
@Table(name = "orders")
@Data
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private Long customerId;
@OneToMany(cascade = CascadeType.ALL)
private List<OrderItem> items;
private BigDecimal totalAmount;
// 状态相关时间字段
private LocalDateTime createdAt = LocalDateTime.now();
private LocalDateTime confirmedAt;
private LocalDateTime paidAt;
private LocalDateTime shippedAt;
private LocalDateTime deliveredAt;
private LocalDateTime cancelledAt;
private String cancellationReason;
private LocalDateTime refundedAt;
@Transient
private OrderState currentState; // 持有当前状态(不持久化到数据库)
@Column(name = "status")
private String status = "NEW"; // 持久化状态标识
// 加载实体时初始化状态(从数据库status字段恢复currentState)
@PostLoad
private void onLoad() {
initState();
}
private void initState() {
if (status == null) status = "NEW";
// 根据状态标识,从Spring容器获取对应的状态实例
switch (status) {
case "NEW":
currentState = SpringContextHolder.getBean(NewOrderState.class);
break;
case "CONFIRMED":
currentState = SpringContextHolder.getBean(ConfirmedOrderState.class);
break;
case "PAID":
currentState = SpringContextHolder.getBean(PaidOrderState.class);
break;
case "SHIPPED":
currentState = SpringContextHolder.getBean(ShippedOrderState.class);
break;
case "DELIVERED":
currentState = SpringContextHolder.getBean(DeliveredOrderState.class);
break;
case "CANCELLED":
currentState = SpringContextHolder.getBean(CancelledOrderState.class);
break;
case "REFUNDED":
currentState = SpringContextHolder.getBean(RefundedOrderState.class);
break;
default:
throw new IllegalStateException("未知订单状态:" + status);
}
}
// 对外暴露的状态切换方法(调用当前状态的对应方法)
public void confirm() {
currentState = currentState.confirm(this);
status = currentState.getStatus(); // 更新持久化的状态标识
}
public void pay() {
currentState = currentState.pay(this);
status = currentState.getStatus();
}
public void ship() {
currentState = currentState.ship(this);
status = currentState.getStatus();
}
public void deliver() {
currentState = currentState.deliver(this);
status = currentState.getStatus();
}
public void cancel() {
currentState = currentState.cancel(this);
status = currentState.getStatus();
}
public void refund() {
currentState = currentState.refund(this);
status = currentState.getStatus();
}
}
// Spring上下文工具:给实体类注入Spring Bean(关键)
@Component
public class SpringContextHolder implements ApplicationContextAware {
private static ApplicationContext context;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
context = applicationContext;
}
// 静态方法获取Bean(实体类无法直接@Autowired,用这个工具类)
public static <T> T getBean(Class<T> clazz) {
return context.getBean(clazz);
}
}
// 订单服务:业务层调用状态切换
@Service
public class OrderService {
@Autowired
private OrderRepository orderRepository;
@Autowired
private NewOrderState initialState; // 初始状态:新建
@Transactional
public Order createOrder(Long customerId, List<OrderItem> items, BigDecimal totalAmount) {
Order order = new Order();
order.setCustomerId(customerId);
order.setItems(items);
order.setTotalAmount(totalAmount);
order.setCurrentState(initialState); // 设置初始状态
return orderRepository.save(order);
}
@Transactional
public Order confirmOrder(Long orderId) {
Order order = findOrderById(orderId);
order.confirm(); // 触发状态切换:NEW → CONFIRMED
return orderRepository.save(order);
}
@Transactional
public Order payOrder(Long orderId) {
Order order = findOrderById(orderId);
order.pay(); // 触发状态切换:CONFIRMED → PAID
return orderRepository.save(order);
}
@Transactional
public Order shipOrder(Long orderId) {
Order order = findOrderById(orderId);
order.ship(); // 触发状态切换:PAID → SHIPPED
return orderRepository.save(order);
}
@Transactional
public Order deliverOrder(Long orderId) {
Order order = findOrderById(orderId);
order.deliver(); // 触发状态切换:SHIPPED → DELIVERED
return orderRepository.save(order);
}
@Transactional
public Order cancelOrder(Long orderId) {
Order order = findOrderById(orderId);
order.cancel(); // 触发状态切换(比如NEW → CANCELLED)
return orderRepository.save(order);
}
@Transactional
public Order refundOrder(Long orderId) {
Order order = findOrderById(orderId);
order.refund(); // 触发状态切换(比如PAID → REFUNDED)
return orderRepository.save(order);
}
private Order findOrderById(Long orderId) {
return orderRepository.findById(orderId)
.orElseThrow(() -> new OrderNotFoundException("订单不存在:" + orderId));
}
// 给外部暴露Repository(命令模式里要用)
public OrderRepository getRepository() {
return orderRepository;
}
}
// 自定义异常:订单不存在
public class OrderNotFoundException extends RuntimeException {
public OrderNotFoundException(String message) {
super(message);
}
}
// 自定义异常:支付失败
public class PaymentFailedException extends RuntimeException {
public PaymentFailedException(String message) {
super(message);
}
}
// 自定义异常:报表导出失败
public class ReportExportException extends RuntimeException {
public ReportExportException(String message, Throwable cause) {
super(message, cause);
}
}
实战优势
状态行为封装: 每个状态的行为都在独立类里,比如 “新建状态能做什么” 全在NewOrderState里,代码清晰,不用翻一堆if-else。
状态切换清晰: 状态之间的流转规则(比如 NEW→CONFIRMED,CONFIRMED→PAID)由状态类自己控制,逻辑不混乱。
易扩展新状态: 新增 “已拒收” 状态,只需写RejectedOrderState类,实现OrderState接口,修改状态流转规则即可,不用改原有状态代码。
避免状态混乱: 每个状态只暴露自己支持的行为,比如 “已支付” 状态不能调用cancel(),从代码层面防止非法操作。
设计模式不是 “银弹”,是 “工具箱”
实际开发中,这些模式很少单独用 —— 比如订单下单流程,会同时用到命令模式(封装每个步骤)、状态模式(管理订单状态)、观察者模式(下单成功后发通知)。
掌握设计模式的核心不是 “死记硬背每种模式的代码”,而是理解它要解决的问题:比如解耦、复用、扩展。遇到复杂业务时,从 “工具箱” 里挑合适的 “工具” 组合使用,而不是为了用模式而用模式(避免过度设计)。
最后记住:代码是给人看的,其次才是给机器执行的。设计模式的最终目的,是让代码更易懂、更易维护 —— 这才是 “优雅代码” 的本质~
要是你还想整点进阶玩法,比如把这些模式整合到一个完整的电商项目里,或者整理成面试高频题 + 答题思路,只管说!咱主打一个有求必应~
- 点赞
- 收藏
- 关注作者
评论(0)