25、设计模式综合实战一:基于Spring Boot实现电商订单系统(单例+工厂+策略+观察者)
终于到了综合实战环节。说实话,前面讲了那么多设计模式,都是一个个孤立的点。今天咱们把它们串起来,做一个真正能跑起来的电商订单系统。我选Spring Boot作为基础框架,因为现在大部分Java后端项目都在用这个。
这个案例我会把单例、工厂、策略、观察者四个模式揉在一起。你想想看,一个订单从创建到完成,中间要经历多少步骤?状态变化、支付方式、通知推送……每个环节都有设计模式的身影。
25.1 系统整体架构
先看整体结构。我画了一张图,把四个模式的关系理清楚。这张图我改了三版,最后定下来这个版本——简洁、清晰、不绕弯子。
看到没?单例模式贯穿全局,工厂负责创建,策略处理支付,观察者处理后续通知。每个模式各司其职,互不干扰。
25.2 单例模式:全局配置管理
先讲单例。为什么第一个实现它?因为配置信息到处都要用。支付接口的URL、短信网关的密钥、库存系统的地址……这些信息如果每个类都自己存一份,改起来就麻烦了。
我个人习惯用枚举实现单例。为什么?因为枚举天然防反射攻击、防序列化破坏。你想想看,如果用双重检查锁,还得写volatile,一不小心就踩坑。
public enum OrderConfigSingleton {
INSTANCE;
private final Properties properties = new Properties();
OrderConfigSingleton() {
// 加载配置文件,只加载一次
try (InputStream is = getClass().getClassLoader()
.getResourceAsStream("order-config.properties")) {
properties.load(is);
} catch (IOException e) {
// 实际项目中应该用日志框架
System.err.println("加载配置失败: " + e.getMessage());
}
}
public String getPaymentGatewayUrl() {
return properties.getProperty("payment.gateway.url");
}
public String getSmsApiKey() {
return properties.getProperty("sms.api.key");
}
public int getOrderTimeoutSeconds() {
return Integer.parseInt(properties.getProperty("order.timeout.seconds", "1800"));
}
}
25.3 工厂模式:创建订单处理器
订单类型有很多种:普通订单、秒杀订单、团购订单、预售订单……每种订单的处理逻辑都不一样。如果直接在代码里写if-else,那维护起来就是噩梦。
工厂模式就是干这个的。它把「创建对象」的逻辑集中管理,调用方只需要告诉工厂「我要什么类型」,工厂就返回对应的处理器。
// 订单处理器接口
public interface OrderHandler {
void handle(Order order);
}
// 普通订单处理器
@Component("normalOrderHandler")
public class NormalOrderHandler implements OrderHandler {
@Override
public void handle(Order order) {
System.out.println("处理普通订单: " + order.getOrderId());
// 正常库存扣减、价格计算等
}
}
// 秒杀订单处理器
@Component("flashOrderHandler")
public class FlashOrderHandler implements OrderHandler {
@Override
public void handle(Order order) {
System.out.println("处理秒杀订单: " + order.getOrderId());
// 秒杀特有的限流、库存校验
}
}
// 工厂类
@Component
public class OrderHandlerFactory {
@Autowired
private Map<String, OrderHandler> handlerMap;
public OrderHandler getHandler(String orderType) {
OrderHandler handler = handlerMap.get(orderType + "OrderHandler");
if (handler == null) {
throw new IllegalArgumentException("不支持的订单类型: " + orderType);
}
return handler;
}
}
这里我用Spring的依赖注入自动收集所有OrderHandler的实现。你想想看,以后新增一种订单类型,只需要写一个新的Handler类,加上@Component注解,工厂自动就能找到它。完全不用改工厂代码——这就是开闭原则。
25.4 策略模式:多种支付方式
支付方式就更典型了。支付宝、微信支付、银行卡、余额支付……每种支付方式的接口、签名算法、回调处理都不一样。策略模式就是为这种场景量身定做的。
// 支付策略接口
public interface PaymentStrategy {
boolean pay(Order order, double amount);
String getChannel();
}
// 支付宝支付
@Component
public class AlipayStrategy implements PaymentStrategy {
@Override
public boolean pay(Order order, double amount) {
System.out.println("支付宝支付: " + amount + " 元");
// 调用支付宝SDK
return true;
}
@Override
public String getChannel() {
return "alipay";
}
}
// 微信支付
@Component
public class WechatPayStrategy implements PaymentStrategy {
@Override
public boolean pay(Order order, double amount) {
System.out.println("微信支付: " + amount + " 元");
// 调用微信支付SDK
return true;
}
@Override
public String getChannel() {
return "wechat";
}
}
// 支付上下文
@Component
public class PaymentContext {
@Autowired
private Map<String, PaymentStrategy> strategyMap;
public boolean executePayment(Order order, String channel) {
PaymentStrategy strategy = strategyMap.get(channel);
if (strategy == null) {
throw new IllegalArgumentException("不支持的支付渠道: " + channel);
}
return strategy.pay(order, order.getTotalAmount());
}
}
25.5 观察者模式:订单状态通知
订单支付成功后,要做什么?发短信通知用户、发邮件给商家、更新库存、记录日志、推送消息给运营后台……这些操作如果都写在支付成功的代码里,那支付方法就会变得臃肿不堪。
观察者模式就是解决这个问题的。支付成功后,只发布一个「订单支付成功」事件,所有关心这个事件的观察者自己去处理。
// 事件对象
public class OrderEvent {
private Order order;
private String eventType; // PAY_SUCCESS, SHIPPED, DELIVERED 等
// getter/setter 省略
}
// 事件发布器
@Component
public class OrderEventPublisher {
@Autowired
private ApplicationEventPublisher publisher;
public void publishOrderEvent(Order order, String eventType) {
OrderEvent event = new OrderEvent();
event.setOrder(order);
event.setEventType(eventType);
publisher.publishEvent(event);
}
}
// 短信观察者
@Component
public class SmsObserver {
@EventListener
public void handleOrderEvent(OrderEvent event) {
if ("PAY_SUCCESS".equals(event.getEventType())) {
System.out.println("发送短信通知用户: 订单 "
+ event.getOrder().getOrderId() + " 支付成功");
}
}
}
// 库存观察者
@Component
public class InventoryObserver {
@EventListener
public void handleOrderEvent(OrderEvent event) {
if ("PAY_SUCCESS".equals(event.getEventType())) {
System.out.println("扣减库存: 订单 "
+ event.getOrder().getOrderId());
}
}
}
// 日志观察者
@Component
public class LogObserver {
@EventListener
public void handleOrderEvent(OrderEvent event) {
System.out.println("记录日志: 订单 "
+ event.getOrder().getOrderId()
+ " 状态变更 -> " + event.getEventType());
}
}
这里我用的是Spring的@EventListener注解,底层就是观察者模式。你想想看,如果以后要增加一个「推送微信模板消息」的功能,只需要再写一个Observer类,完全不用动已有的代码。
25.6 整合:订单服务主流程
好了,四个模式都实现了。现在把它们串起来,看看一个完整的订单创建流程是什么样的。
@Service
public class OrderService {
@Autowired
private OrderHandlerFactory handlerFactory;
@Autowired
private PaymentContext paymentContext;
@Autowired
private OrderEventPublisher eventPublisher;
@Autowired
private OrderConfigSingleton config; // 单例注入
public void createOrder(OrderRequest request) {
// 1. 创建订单对象
Order order = new Order();
order.setOrderId(UUID.randomUUID().toString());
order.setType(request.getOrderType());
order.setTotalAmount(request.getAmount());
// 2. 工厂模式:获取对应的订单处理器
OrderHandler handler = handlerFactory.getHandler(order.getType());
handler.handle(order);
// 3. 策略模式:执行支付
boolean paid = paymentContext.executePayment(order, request.getPaymentChannel());
if (!paid) {
throw new RuntimeException("支付失败");
}
// 4. 观察者模式:发布支付成功事件
eventPublisher.publishOrderEvent(order, "PAY_SUCCESS");
System.out.println("订单创建完成: " + order.getOrderId());
}
}
看到没?整个流程清晰得像流水线。每个模式只负责自己那一块,互不干扰。这就是设计模式组合使用的魅力。
25.7 避坑与经验总结
最后聊几个我在实战中踩过的坑,希望对你有帮助。
| 模式 | 常见坑点 | 我的建议 |
|---|---|---|
| 单例 | 线程安全问题、序列化破坏 | 用枚举实现,一劳永逸 |
| 工厂 | 类型过多导致工厂膨胀 | 结合Spring的依赖注入自动注册 |
| 策略 | 策略类数量爆炸 | 用Map管理,按需加载 |
| 观察者 | 事件处理异常导致主流程中断 | 异步处理,或者加try-catch |
好了,这一章的内容就到这里。四个模式组合使用,其实并不复杂。关键是理解每个模式的职责边界,不要越界。工厂只负责创建,策略只负责算法,观察者只负责通知,单例只负责配置。各司其职,系统自然就清晰了。
公众号:蓝海资料掘金营,微信deep3321