使用策略模式+模板方法优化订单类型处理

背景分析
在系统(如电商)中,我们经常需要根据不同的订单类型(如商品、课程、包间等)执行差异化的处理逻辑。传统的实现方式往往会使用多重if-else判断,但随着业务扩展,这种实现会面临以下问题:

​开闭原则破坏:新增订单类型需要修改核心处理逻辑
​可维护性差:业务逻辑分散在不同条件分支中
​可测试性差:难以进行单元测试和模拟测试

优化前

原先的if判断,根据订单类别选择插入数据

        //订单是商品
        if (dto.getOrderType() == NumberEnum.ONE.getValue()) {
            orderProductService.saveOrderProduct(orderId, dto.getOrderProducts());
            //进行商品扣减
            dto.getOrderProducts().forEach(orderProduct -> productsService.deductionProduct(orderProduct.getProductId(), orderProduct.getQuantity()));
            return handleResult(save, "购买成功", "购买失败");
        }

        //订单是课程
        if (dto.getOrderType() == NumberEnum.TWO.getValue()) {
            //报名课程
            Result voidResult = coursesService.joinCourse(dto.getOrderCourse().getCourseId());
            orderCourseService.saveOrderCourse(orderId, dto.getOrderCourse());
            return voidResult;
        }

        //订单是包间
        if (dto.getOrderType() == NumberEnum.THREE.getValue()) {
            Result voidResult = roomsService.reserveRoom(dto.getReserveRoom());
            orderRoomService.saveOrderRoom(orderId, dto.getReserveRoom());
            //预约包间
            return voidResult;
        }

优化后

定义模板接口

public interface OrderTypeHandler {
    /**
     * 订单处理接口方法
     *
     * @param orderId 订单id
     * @param dto     订单信息DTO
     * @author 杜伟毅
     * @since 2025/3/11 0011 22:39
     */
    void handle(String orderId, OrderDTO dto);

    /**
     * 订单删除接口方法
     *
     * @param orderId 订单id
     * @author 杜伟毅
     * @since 2025/3/13 0013 11:11
     */
    void deleteHandle(String orderId);

    /**
     * 获取订单详情方法
     *
     * @param orderVO 订单VO
     * @return 对函数返回值的描述
     * @author 杜伟毅
     * @since 2025/3/13 0013 12:56
     */
    OrderVO getDetailsHandle(OrderVO orderVO);
}

实现接口,自定义bean名字

@Component("courseOrderHandler")
public class CourseOrderHandler implements OrderTypeHandler {}
@Component("productOrderHandler")
public class ProductOrderHandler implements OrderTypeHandler {}
@Component("roomOrderHandler")
public class RoomOrderHandler implements OrderTypeHandler {}

定义枚举

@Getter
public enum OrderTypeEnum {
    PRODUCT(1, "productOrderHandler"),
    COURSE(2, "courseOrderHandler"),
    ROOM(3, "roomOrderHandler");

    private final int code;
    private final String handlerName;

    OrderTypeEnum(int code, String handlerName) {
        this.code = code;
        this.handlerName = handlerName;
    }

    /**
     * 根据订单类型返回实现类
     *
     * @param code 订单类型
     * @return 1:productOrderHandler 2:courseOrderHandler 3:roomOrderHandler
     * @author 杜伟毅
     * @since 2025/3/11 0011 23:11
     */
    public static String getHandlerNameByCode(int code) {
        return Arrays.stream(values())
                .filter(type -> type.code == code)
                .findFirst()
                .orElseThrow(() -> new IllegalArgumentException("无效的订单类型"))
                .handlerName;
    }

    /**
     * 检测是否是合法订单类型
     *
     * @param value 订单类型数字
     * @return 对函数返回值的描述
     * @author 杜伟毅
     * @since 2025/3/11 0011 23:15
     */
    public static boolean isValidOrderTypeEnum(int value) {
        for (OrderTypeEnum orderTypeEnum : OrderTypeEnum.values()) {
            if (value == orderTypeEnum.code) {
                return true;
            }
        }
        return false;
    }
}

使用

	//通过 Spring 的依赖注入机制,将一组 OrderTypeHandler 实现类注入到一个 Map 中,从而实现根据订单类型动态分发处理逻辑的功能。    
	@Resource
    private Map<String, OrderTypeHandler> orderTypeHandlers;

	//使用辅助方法
    /**
     * 根据订单类型获取处理器
     *
     * @param orderType 订单类型
     * @author 杜伟毅
     * @since 2025/3/11 0011 22:58
     */
    private OrderTypeHandler getHandler(Integer orderType) {
        String handlerName = OrderTypeEnum.getHandlerNameByCode(orderType);
        return Optional.ofNullable(orderTypeHandlers.get(handlerName))
                .orElseThrow(() -> new IllegalArgumentException("找不到订单处理器"));
    }


		//   只需要在订单方法中使用一段代码即可

	     //根据订单类型选择
        OrderTypeHandler handler = getHandler(dto.getOrderType());
        handler.handle(orderId, dto);
适用场景建议
  • 存在多个相似处理流程的业务分支
  • 需要支持动态扩展的业务类型
  • 对代码可维护性要求较高的项目
  • 需要统一处理横切关注点的系统

该方案通过组合多种设计模式,有效解决了传统条件判断带来的维护性问题,同时保持了良好的扩展性和可测试性。实际应用中可根据具体业务需求灵活调整模板方法的步骤组成和策略实现方式。

你可能感兴趣的:(策略模式,java)