深入实战模板方法模式与装饰器模式:模板方法模式与装饰器模式在电商系统中的应用

我将分享两种不太常见但非常实用的设计模式在Spring Boot项目中的实际应用:模板方法模式和装饰器模式。这些模式在电商系统中能优雅地解决一些特定问题。

1. 模板方法模式在订单处理流程中的应用

业务场景

电商系统中,不同类型的订单(普通订单、团购订单、秒杀订单)有相似的处理流程,但某些步骤的实现细节不同。例如:

  1. 所有订单都需要验证、计算价格、扣减库存、创建支付
  2. 但团购订单需要额外验证成团状态
  3. 秒杀订单需要验证秒杀资格

代码实现

定义订单处理的抽象模板:

java 复制代码
public abstract class AbstractOrderProcessor {
    
    // 模板方法,定义处理流程
    public final OrderProcessResult process(OrderContext context) {
        validate(context);
        calculatePrice(context);
        if (needSpecificCheck(context)) {
            specificCheck(context);
        }
        deductInventory(context);
        createPayment(context);
        return buildResult(context);
    }
    
    // 通用步骤
    protected void validate(OrderContext context) {
        // 通用验证逻辑
        if (context.getItems().isEmpty()) {
            throw new IllegalArgumentException("订单商品不能为空");
        }
    }
    
    protected void calculatePrice(OrderContext context) {
        // 通用价格计算逻辑
        BigDecimal total = context.getItems().stream()
                .map(item -> item.getPrice().multiply(BigDecimal.valueOf(item.getQuantity())))
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        context.setTotalAmount(total);
    }
    
    protected void deductInventory(OrderContext context) {
        // 通用库存扣减逻辑
        inventoryService.batchDeduct(context.getItems());
    }
    
    protected void createPayment(OrderContext context) {
        // 通用支付创建逻辑
        paymentService.createPayment(context.getOrderId(), context.getTotalAmount());
    }
    
    protected OrderProcessResult buildResult(OrderContext context) {
        return new OrderProcessResult(true, "订单处理成功", context.getOrderId());
    }
    
    // 钩子方法,子类可覆盖
    protected boolean needSpecificCheck(OrderContext context) {
        return false;
    }
    
    // 抽象方法,子类必须实现
    protected abstract void specificCheck(OrderContext context);
    
    @Autowired
    private InventoryService inventoryService;
    
    @Autowired
    private PaymentService paymentService;
}

实现具体订单处理器:

java 复制代码
@Service
public class NormalOrderProcessor extends AbstractOrderProcessor {
    @Override
    protected void specificCheck(OrderContext context) {
        // 普通订单无需特殊检查
    }
    
    @Override
    protected boolean needSpecificCheck(OrderContext context) {
        return false;
    }
}

@Service
public class GroupBuyOrderProcessor extends AbstractOrderProcessor {
    @Override
    protected void specificCheck(OrderContext context) {
        // 团购订单特殊检查
        if (!groupBuyService.isGroupValid(context.getGroupId())) {
            throw new BusinessException("团购活动已结束或人数不足");
        }
    }
    
    @Override
    protected boolean needSpecificCheck(OrderContext context) {
        return true;
    }
    
    @Autowired
    private GroupBuyService groupBuyService;
}

@Service
public class FlashSaleOrderProcessor extends AbstractOrderProcessor {
    @Override
    protected void specificCheck(OrderContext context) {
        // 秒杀订单特殊检查
        if (!flashSaleService.checkQualification(context.getUserId(), context.getFlashSaleId())) {
            throw new BusinessException("您不符合秒杀资格");
        }
    }
    
    @Override
    protected boolean needSpecificCheck(OrderContext context) {
        return true;
    }
    
    @Autowired
    private FlashSaleService flashSaleService;
}

使用工厂获取具体处理器:

java 复制代码
@Service
public class OrderProcessorFactory {
    private final Map<OrderType, AbstractOrderProcessor> processorMap;
    
    public OrderProcessorFactory(List<AbstractOrderProcessor> processors) {
        processorMap = processors.stream()
                .collect(Collectors.toMap(
                    processor -> OrderType.valueOf(processor.getClass()
                            .getSimpleName()
                            .replace("OrderProcessor", "")
                            .toUpperCase()),
                    Function.identity()
                ));
    }
    
    public AbstractOrderProcessor getProcessor(OrderType type) {
        return processorMap.get(type);
    }
}

在控制器中使用:

java 复制代码
@RestController
@RequestMapping("/orders")
public class OrderController {
    private final OrderProcessorFactory processorFactory;
    
    @PostMapping
    public OrderProcessResult createOrder(@RequestBody OrderRequest request) {
        AbstractOrderProcessor processor = processorFactory.getProcessor(request.getType());
        return processor.process(convertToContext(request));
    }
    
    private OrderContext convertToContext(OrderRequest request) {
        // 转换逻辑
    }
}

优势分析

  1. 将不变逻辑放在父类,可变逻辑放在子类,符合开闭原则
  2. 避免代码重复,公共逻辑得到复用
  3. 新增订单类型只需新增子类,不影响现有逻辑
  4. 流程控制集中在父类,便于统一管理和维护

2. 装饰器模式在API响应处理中的应用

业务场景

我们需要对API响应进行多种处理:

  1. 基础响应包装
  2. 数据脱敏(如手机号、身份证号)
  3. 数据格式转换(如日期格式)
  4. 多语言支持
  5. 响应压缩(对大响应)

这些处理可能需要灵活组合使用。

代码实现

定义响应处理器接口:

java 复制代码
public interface ResponseProcessor {
    Object process(Object response);
}

基础实现:

java 复制代码
@Service
public class BasicResponseProcessor implements ResponseProcessor {
    @Override
    public Object process(Object response) {
        if (response == null) {
            return ApiResponse.success();
        }
        return ApiResponse.success(response);
    }
}

抽象装饰器:

java 复制代码
public abstract class ResponseProcessorDecorator implements ResponseProcessor {
    protected final ResponseProcessor wrapped;
    
    public ResponseProcessorDecorator(ResponseProcessor wrapped) {
        this.wrapped = wrapped;
    }
    
    @Override
    public Object process(Object response) {
        return wrapped.process(response);
    }
}

具体装饰器实现:

java 复制代码
@Service
public class DataMaskingDecorator extends ResponseProcessorDecorator {
    public DataMaskingDecorator(ResponseProcessor wrapped) {
        super(wrapped);
    }
    
    @Override
    public Object process(Object response) {
        Object processed = super.process(response);
        return maskSensitiveData(processed);
    }
    
    private Object maskSensitiveData(Object data) {
        // 使用反射或JSON遍历实现数据脱敏
        // 例如将"13812345678"转为"138****5678"
        return data;
    }
}

@Service
public class DateFormatDecorator extends ResponseProcessorDecorator {
    public DateFormatDecorator(ResponseProcessor wrapped) {
        super(wrapped);
    }
    
    @Override
    public Object process(Object response) {
        Object processed = super.process(response);
        return formatDates(processed);
    }
    
    private Object formatDates(Object data) {
        // 统一格式化日期字段
        return data;
    }
}

@Service
public class I18nDecorator extends ResponseProcessorDecorator {
    private final MessageSource messageSource;
    
    public I18nDecorator(ResponseProcessor wrapped, MessageSource messageSource) {
        super(wrapped);
        this.messageSource = messageSource;
    }
    
    @Override
    public Object process(Object response) {
        Object processed = super.process(response);
        return translateMessages(processed);
    }
    
    private Object translateMessages(Object data) {
        // 处理多语言消息
        return data;
    }
}

使用装饰器链:

java 复制代码
@RestControllerAdvice
public class ApiResponseAdvice implements ResponseBodyAdvice<Object> {
    private final ResponseProcessor responseProcessor;
    
    public ApiResponseAdvice(
            BasicResponseProcessor basicProcessor,
            DataMaskingDecorator maskingDecorator,
            DateFormatDecorator dateFormatDecorator,
            I18nDecorator i18nDecorator) {
        // 构建装饰器链
        this.responseProcessor = i18nDecorator;
        ((I18nDecorator) this.responseProcessor).setWrapped(dateFormatDecorator);
        ((DateFormatDecorator) dateFormatDecorator).setWrapped(maskingDecorator);
        ((DataMaskingDecorator) maskingDecorator).setWrapped(basicProcessor);
    }
    
    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
        return true;
    }
    
    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, 
            MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, 
            ServerHttpRequest request, ServerHttpResponse response) {
        return responseProcessor.process(body);
    }
}

优势分析

  1. 可以动态添加或移除功能,比继承更灵活
  2. 每个装饰器只关注一个功能,符合单一职责原则
  3. 装饰顺序可以灵活调整,满足不同场景需求
  4. 运行时组合功能,而非编译时确定

总结

模板方法模式和装饰器模式在Spring Boot项目中有着独特的价值:

  1. ​模板方法模式​适用于有固定流程但某些步骤需要不同实现的场景,如订单处理、工作流引擎等
  2. ​装饰器模式​适用于需要动态添加功能的场景,如API响应处理、IO流处理等

这两种模式都能帮助我们构建更灵活、更易维护的系统架构。在实际项目中,我们应该根据具体业务场景选择合适的设计模式,而不是为了使用模式而使用模式。

相关推荐
乌暮1 小时前
Spring AOP 与 Spring 事务:用大白话彻底理解原理与实践
java·数据库·spring boot·后端·sql·学习·spring
我不会起名字3221 小时前
未接入最终读上限的参数:`websocketMaxMsgLen` 与 12.5 倍差距
后端·websocket·go·即时通讯·im·故障排查
一条Go2 小时前
接收方合并去重:同一个人为什么只该收到一次通知
后端·架构·github
张一凡933 小时前
给 Coding Agent 加一道"架构闸门":Jin 是如何做到"先审架构、再写代码、不漂移"的
前端·后端·agent
Jvav练习生3 小时前
AI Agent 总在关键时刻“失忆”翻车?一文讲透上下文工程(附可运行 Python 代码)
后端
leo在掘金3 小时前
只挂了11小时,5000台开发机被塞进SSH公钥
后端·架构
xjz18423 小时前
Rust 运算符优先级:括号不只用来改变顺序
后端
写码跑山的老艾3 小时前
为什么有了 MySQL,还要 Redis 和 Elasticsearch?从一件商品看数据系统的权衡
后端
对象存储与RustFS3 小时前
Jenkins 的构建产物别堆在控制器磁盘:用 RustFS 当它的 S3 工件仓库
后端·docker·云原生