欢迎光临
我们一直在努力

SpringBoot中设计模式组合使用示例-策略、模板、观察者、门面、工厂、单例。

SpringBoot中设计模式组合使用示例-策略、模板、观察者、门面、工厂、单例。


注:

博客:

https://blog.csdn.net/badao_liumang_qizhi

一、策略模式(Strategy Pattern)

概念

定义一组算法/行为,将每个算法封装成独立的处理单元,使它们可以互相替换。客户端根据条件选择使用哪个策略。

解决的问题

避免大量的 if-else 或 switch-case 散落在业务逻辑中,新增策略时不需要修改已有代码。

项目中的体现

根据物流节点编码路由到不同处理方法:

switch (OpCodeEnums.valueOfCode(paramsDto.getOpCode())) {
case a: this.aHandle(...); break;
case b: this.bHandle(...); break;
case c: this.cHandle(...); break;
// …
}

每个 case 分支对应一个独立的处理策略。新增事件只需添加一个 case 和对应方法。

通用代码示例

/**
* 策略接口:定义统一的处理行为.
*/

public interface PaymentStrategy {
/** 执行支付. */
PayResult pay(PayRequest request);
/** 是否支持该支付方式. */
boolean support(String payType);
}

/**
* 具体策略:微信支付.
*/

@Component
public class WechatPayStrategy implements PaymentStrategy {
@Override
public PayResult pay(PayRequest request) {
// 调用微信支付 API
return new PayResult(true, "微信支付成功");
}

@Override
public boolean support(String payType) {
return "WECHAT".equals(payType);
}
}

/**
* 具体策略:支付宝支付.
*/

@Component
public class AlipayStrategy implements PaymentStrategy {
@Override
public PayResult pay(PayRequest request) {
// 调用支付宝 API
return new PayResult(true, "支付宝支付成功");
}

@Override
public boolean support(String payType) {
return "ALIPAY".equals(payType);
}
}

/**
* 策略上下文:根据条件选择策略并执行.
* Spring 自动注入所有 PaymentStrategy 实现.
*/

@Service
public class PaymentService {

@Resource
private List<PaymentStrategy> strategies;

public PayResult pay(String payType, PayRequest request) {
PaymentStrategy strategy = strategies.stream()
.filter(s -> s.support(payType))
.findFirst()
.orElseThrow(() -> new RuntimeException("不支持的支付方式: " + payType));
return strategy.pay(request);
}
}

类图

┌────────────────────┐
│ PaymentService │ (上下文,选择策略)
│ – strategies │
│ + pay() │
└────────┬───────────┘
│ 持有

┌────────────────────┐
│ <<interface>> │
│ PaymentStrategy │
│ + pay() │
│ + support() │
└────────┬───────────┘
│ 实现
┌────┴────┐
▼ ▼
┌────────┐ ┌────────┐
│Wechat │ │Alipay │
│Strategy│ │Strategy│
└────────┘ └────────┘


二、模板方法模式(Template Method Pattern)

概念

在父类中定义一个算法的骨架(步骤顺序),将某些步骤的具体实现延迟到子类或通过参数差异化。整体流程不变,只是个别步骤的行为不同。

解决的问题

多个流程整体结构相同,只有部分细节不同。避免重复代码,把共同逻辑抽到一处。

项目中的体现

方法是一个固定模板,不同事件(a/b/c)走同一套流程:

① 判断是否指定类型订单 → 所有事件都一样
② 构造 DTO → event 字段不同
③ 写日志表 → 所有事件都一样
④ 注册事务回调发MQ → 所有事件都一样
⑤ 调用标签推送 → 根据 event 设置不同标签

调用方只需传入不同的 event 参数:

aaService.interceptNodeTobb(data, recordItem, "a");
aasService.interceptNodeTobb(data, recordItem, "b");
aasService.interceptNodeTobb(data, recordItem, "c");

通用代码示例

/**
* 抽象模板类:定义导出流程骨架.
*/

public abstract class AbstractExportTemplate {

/**
* 模板方法:固定的执行步骤.
* final 防止子类覆盖整体流程.
*/

public final void export(ExportRequest request) {
// 步骤1:校验参数(通用)
validate(request);
// 步骤2:查询数据(子类实现)
List<Object> data = queryData(request);
// 步骤3:转换格式(子类实现)
byte[] content = convertToFile(data, request.getFileType());
// 步骤4:上传文件(通用)
upload(content, request.getFileName());
// 步骤5:发送通知(通用)
notify(request.getUserId(), request.getFileName());
}

private void validate(ExportRequest request) {
if (request.getUserId() == null) {
throw new IllegalArgumentException("用户ID不能为空");
}
}

/** 子类实现:查询数据. */
protected abstract List<Object> queryData(ExportRequest request);

/** 子类实现:转换为文件内容. */
protected abstract byte[] convertToFile(List<Object> data, String fileType);

private void upload(byte[] content, String fileName) {
// 上传到 OSS
}

private void notify(Integer userId, String fileName) {
// 发送消息通知用户
}
}

/**
* 具体实现:订单导出.
*/

@Service
public class OrderExportService extends AbstractExportTemplate {

@Override
protected List<Object> queryData(ExportRequest request) {
return orderRepository.findByCondition(request.getCondition());
}

@Override
protected byte[] convertToFile(List<Object> data, String fileType) {
if ("excel".equals(fileType)) {
return ExcelUtil.toExcel(data);
}
return CsvUtil.toCsv(data);
}
}

/**
* 具体实现:库存导出.
*/

@Service
public class StockExportService extends AbstractExportTemplate {

@Override
protected List<Object> queryData(ExportRequest request) {
return stockRepository.findByWarehouseId(request.getWarehouseId());
}

@Override
protected byte[] convertToFile(List<Object> data, String fileType) {
return ExcelUtil.toExcel(data);
}
}

类图

┌──────────────────────────────┐
│ AbstractExportTemplate │
│ │
│ + export() [final, 模板方法] │
│ – validate() │
│ # queryData() [abstract] │
│ # convertToFile() [abstract] │
│ – upload() │
│ – notify() │
└──────────────┬───────────────┘
│ 继承
┌──────┴──────┐
▼ ▼
┌──────────────┐ ┌──────────────┐
│OrderExport │ │StockExport │
│Service │ │Service │
└──────────────┘ └──────────────┘


三、观察者模式(Observer Pattern)

概念

定义对象间的一对多依赖关系,当一个对象状态改变时,所有依赖它的对象都得到通知并自动更新。

解决的问题

一件事发生后需要触发多个后续动作,但不想把这些动作硬编码在主流程中。

项目中的体现

Spring 的 TransactionSynchronizationManager 就是观察者模式的应用:

// 事务是被观察的"主题"
// AfterTransactionActionCollector 是"观察者"
// 事务提交这个"事件"触发观察者执行
AfterTransactionActionCollector collector = new AfterTransactionActionCollector();
TransactionSynchronizationManager.registerSynchronization(collector);
collector.addCommitSyncAction(() -> sendJstMessageMqSender.sendJstMessageMq(recordLog.getId()));

事务提交后,所有注册的同步回调自动被触发执行。

通用代码示例

方式一:Spring 事件机制

/**
* 事件定义:订单创建事件.
*/

public class OrderCreatedEvent extends ApplicationEvent {
private final String orderCode;
private final Integer userId;

public OrderCreatedEvent(Object source, String orderCode, Integer userId) {
super(source);
this.orderCode = orderCode;
this.userId = userId;
}

public String getOrderCode() { return orderCode; }
public Integer getUserId() { return userId; }
}

/**
* 事件发布者:订单服务.
* 只负责发布事件,不关心谁在监听.
*/

@Service
public class OrderService {

@Resource
private ApplicationEventPublisher eventPublisher;

@Transactional
public void createOrder(OrderDto dto) {
// 核心业务:创建订单
Order order = orderRepository.save(buildOrder(dto));

// 发布事件(不关心后续处理)
eventPublisher.publishEvent(
new OrderCreatedEvent(this, order.getOrderCode(), dto.getUserId()));
}
}

/**
* 观察者1:发送短信通知.
*/

@Component
public class SmsNotificationListener {

@EventListener
public void onOrderCreated(OrderCreatedEvent event) {
smsService.send(event.getUserId(), "您的订单已创建:" + event.getOrderCode());
}
}

/**
* 观察者2:初始化物流信息.
*/

@Component
public class LogisticsInitListener {

@EventListener
public void onOrderCreated(OrderCreatedEvent event) {
logisticsService.initLogisticsRecord(event.getOrderCode());
}
}

/**
* 观察者3:异步更新统计报表.
*/

@Component
public class ReportListener {

@Async
@EventListener
public void onOrderCreated(OrderCreatedEvent event) {
reportService.incrementDailyCount();
}
}

方式二:事务提交后回调

/**
* 事务提交后触发动作.
* 确保数据库操作成功后才执行副作用(发MQ、调接口等).
*/

@Service
public class InventoryService {

public void deductStock(Integer skuId, Integer quantity) {
// 扣减库存(数据库操作)
stockRepository.deduct(skuId, quantity);

// 注册事务提交后的回调
TransactionSynchronizationManager.registerSynchronization(
new TransactionSynchronization() {
@Override
public void afterCommit() {
// 事务成功后才通知下游
mqSender.sendStockChanged(skuId);
cacheService.invalidate("stock:" + skuId);
}

@Override
public void afterCompletion(int status) {
if (status == STATUS_ROLLED_BACK) {
log.warn("事务回滚,不发送通知");
}
}
}
);
}
}

类图

┌───────────────────────┐
│ ApplicationEvent │ (事件)
│ Publisher │
│ + publishEvent() │
└───────────┬───────────┘
│ 发布

┌───────────────────────┐ ┌─────────────────┐
│ OrderCreatedEvent │──────→│ SmsListener │ 观察者1
└───────────────────────┘ 通知 ├─────────────────┤
────→│ LogisticsListener│ 观察者2
────→│ ReportListener │ 观察者3
└─────────────────┘


四、门面模式(Facade Pattern)

概念

为复杂子系统提供一个简化的统一接口。调用方不需要了解子系统内部的复杂性,只需通过门面接口完成操作。

解决的问题

子系统内部有多个类、多个步骤协作,直接暴露给调用方会导致耦合度高、使用复杂。

项目中的体现

aaService 接口就是门面——封装了与 bb 交互的所有复杂逻辑:

// 调用方一行代码搞定
aaService.interceptNodeTobb(data, recordItem, "a");

内部实际做了 5 件事:

  • 查询是否 指定类型订单(调远程 Feign)
  • 构造 DTO
  • 写数据库日志表
  • 注册事务同步回调
  • 发 MQ
  • 调用方无需知道这些细节。

    通用代码示例

    /**
    * 门面接口:对外暴露的简化接口.
    */

    public interface OrderFacade {
    /** 一键下单(内部协调多个子系统). */
    OrderResult placeOrder(PlaceOrderRequest request);
    }

    /**
    * 门面实现:协调多个子系统完成复杂操作.
    */

    @Service
    @Slf4j
    public class OrderFacadeImpl implements OrderFacade {

    @Resource private InventoryService inventoryService; // 库存子系统
    @Resource private PaymentService paymentService; // 支付子系统
    @Resource private LogisticsService logisticsService; // 物流子系统
    @Resource private NotificationService notificationService; // 通知子系统

    @Override
    @Transactional(rollbackFor = Exception.class)
    public OrderResult placeOrder(PlaceOrderRequest request) {
    // 1. 检查库存
    boolean hasStock = inventoryService.checkAndLock(
    request.getSkuId(), request.getQuantity());
    if (!hasStock) {
    return OrderResult.fail("库存不足");
    }

    // 2. 创建支付单
    String payNo = paymentService.createPayOrder(
    request.getUserId(), request.getAmount());

    // 3. 预分配物流
    logisticsService.preAllocate(request.getAddress());

    // 4. 发送通知
    notificationService.sendOrderCreated(request.getUserId());

    return OrderResult.success(payNo);
    }
    }

    /**
    * 调用方:只需面对门面接口,不关心内部有哪些子系统.
    */

    @RestController
    public class OrderController {

    @Resource
    private OrderFacade orderFacade;

    @PostMapping("/order/place")
    public Result<OrderResult> placeOrder(@RequestBody PlaceOrderRequest request) {
    return Result.success(orderFacade.placeOrder(request));
    }
    }

    类图

    ┌────────────┐ ┌─────────────────────────────────────┐
    │ Controller │ │ OrderFacade (门面) │
    │ │─────────→│ │
    └────────────┘ │ 内部协调: │
    │ ┌─────────────┐ ┌───────────────┐ │
    │ │ Inventory │ │ Payment │ │
    │ │ Service │ │ Service │ │
    │ └─────────────┘ └───────────────┘ │
    │ ┌─────────────┐ ┌───────────────┐ │
    │ │ Logistics │ │ Notification │ │
    │ │ Service │ │ Service │ │
    │ └─────────────┘ └───────────────┘ │
    └─────────────────────────────────────┘


    五、工厂模式(Factory Pattern)

    概念

    将对象的创建逻辑封装到工厂类中,调用方不直接 new 对象,而是通过工厂获取。

    解决的问题

    对象创建逻辑复杂,或需要根据条件创建不同类型的对象。

    项目中的体现

    Feign 的 FallbackFactory 就是工厂模式——根据异常类型创建不同的降级实例:

    @FeignClient(fallbackFactory = aaaOrderFallbackFactory.class)
    public interface aaaOrderFeign { ... }

    FallbackFactory 接口:

    public interface FallbackFactory<T> {
    T create(Throwable cause); // 工厂方法:根据异常创建降级实例
    }

    通用代码示例

    /**
    * 产品接口:消息发送器.
    */

    public interface MessageSender {
    void send(String target, String content);
    }

    /**
    * 具体产品:短信发送.
    */

    @Component("SMS")
    public class SmsSender implements MessageSender {
    @Override
    public void send(String target, String content) {
    // 调用短信平台 API
    }
    }

    /**
    * 具体产品:邮件发送.
    */

    @Component("EMAIL")
    public class EmailSender implements MessageSender {
    @Override
    public void send(String target, String content) {
    // 调用邮件服务
    }
    }

    /**
    * 具体产品:站内信.
    */

    @Component("INNER_MSG")
    public class InnerMsgSender implements MessageSender {
    @Override
    public void send(String target, String content) {
    // 写入消息表
    }
    }

    /**
    * 工厂类:根据类型获取对应的发送器.
    * 利用 Spring 的 Map 注入自动收集所有实现.
    */

    @Component
    public class MessageSenderFactory {

    /** Spring 自动按 Bean 名称注入到 Map 中. */
    @Resource
    private Map<String, MessageSender> senderMap;

    public MessageSender getSender(String type) {
    MessageSender sender = senderMap.get(type);
    if (sender == null) {
    throw new RuntimeException("不支持的消息类型: " + type);
    }
    return sender;
    }
    }

    /**
    * 使用示例.
    */

    @Service
    public class NoticeService {

    @Resource
    private MessageSenderFactory factory;

    public void sendNotice(String type, String target, String content) {
    MessageSender sender = factory.getSender(type);
    sender.send(target, content);
    }
    }


    六、代理模式(Proxy Pattern)

    概念

    为其他对象提供一种代理,以控制对这个对象的访问。代理对象在调用真实对象前后可以加入额外逻辑。

    解决的问题

    在不修改原有逻辑的前提下增加横切关注点(日志、鉴权、缓存、重试等)。

    项目中的体现

  • Feign 本身就是动态代理——你写的是接口,Feign 通过 JDK 动态代理生成实现类
  • Spring AOP(@Transactional)——事务管理通过代理实现
  • FallbackFactory——代理原始 Feign 接口,在调用失败时走降级逻辑
  • // 你写的只是接口
    @FeignClient(value = "aaa-order")
    public interface aaaOrderFeign {
    @PostMapping("/aaa/order/result/receive")
    RestControllerResult<Boolean> noticeAa(@RequestBody aaOperationDto param);
    }

    // Feign 框架在运行时生成代理类,大致逻辑:

    通用代码示例

    /**
    * 接口定义.
    */

    public interface DataService {
    String getData(String key);
    }

    /**
    * 真实实现:从数据库查询.
    */

    @Service("dataServiceImpl")
    public class DataServiceImpl implements DataService {
    @Override
    public String getData(String key) {
    // 模拟耗时的数据库查询
    return database.query(key);
    }
    }

    /**
    * 代理实现:增加缓存逻辑.
    * 先查缓存,缓存没有再调真实实现.
    */

    @Service
    @Primary
    public class CachedDataServiceProxy implements DataService {

    @Resource
    @Qualifier("dataServiceImpl")
    private DataService realService;

    @Resource
    private RedisTemplate<String, String> redisTemplate;

    @Override
    public String getData(String key) {
    // 先查缓存
    String cached = redisTemplate.opsForValue().get("cache:" + key);
    if (cached != null) {
    return cached;
    }
    // 缓存未命中,调用真实实现
    String data = realService.getData(key);
    // 写入缓存
    redisTemplate.opsForValue().set("cache:" + key, data, 5, TimeUnit.MINUTES);
    return data;
    }
    }


    七、单例模式(Singleton Pattern)

    概念

    确保一个类只有一个实例,并提供全局访问点。

    项目中的体现

    Spring Bean 默认就是单例的。项目中所有 @Service、@Component 注解的类在容器中只有一个实例:

    @Service
    public class OmsServiceImpl implements OmsService { ... } // 单例

    @Component
    public class EventCenterUtil { ... } // 单例

    通用代码示例

    /**
    * 方式一:Spring 管理的单例(推荐).
    * 通过 @Component/@Service 注解,Spring 容器保证单例.
    */

    @Component
    public class GlobalConfig {
    private Map<String, String> configMap = new ConcurrentHashMap<>();

    public String get(String key) {
    return configMap.get(key);
    }

    public void set(String key, String value) {
    configMap.put(key, value);
    }
    }

    /**
    * 方式二:双重检查锁(非 Spring 环境).
    */

    public class ConnectionPool {
    private static volatile ConnectionPool instance;

    private ConnectionPool() {
    // 初始化连接池
    }

    public static ConnectionPool getInstance() {
    if (instance == null) {
    synchronized (ConnectionPool.class) {
    if (instance == null) {
    instance = new ConnectionPool();
    }
    }
    }
    return instance;
    }
    }

    赞(0)
    未经允许不得转载:171主机测评 » SpringBoot中设计模式组合使用示例-策略、模板、观察者、门面、工厂、单例。
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址