策略+工厂设计模式【如何避免在你的代码中出现大量的if-else】

4 阅读2分钟

1、先给所有的策略装配到一个枚举类

/**
 * 回调类型枚举:统一管理所有支持的回调类型
 */
@Getter
@AllArgsConstructor
public enum CallbackTypeEnum {
    ORDER_CALLBACK("order", "订单回调"),
    PAYMENT_CALLBACK("payment", "支付回调"),
    SHIPPING_CALLBACK("shipping", "物流回调");
    
    private final String code;        // 与回调参数中的值对应
    private final String description; // 类型描述
    
    /**
     * 根据code查找枚举
     */
    public static CallbackTypeEnum getByCode(String code) {
        for (CallbackTypeEnum value : values()) {
            if (value.getCode().equals(code)) {
                return value;
            }
        }
        throw new IllegalArgumentException("未支持的回调类型: " + code);
    }
}

2、写一个自定义注解,就是为了将枚举类的值跟匹配的handler连接

/**
 * 策略类型注解:用于标记策略类对应的回调类型
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface OrderStrategyType {
    CallbackTypeEnum value();
}

策略类

/**
 * 日志更新策略接口
 */
public interface LogUpdateStrategy {
    /**
     * 更新日志
     * @param callbackResult 回调结果
     */
    void updateLog(CallbackResult callbackResult);
}

实现类

/**
 * 支付回调日志更新策略
 */
@Component
@OrderStrategyType(CallbackTypeEnum.PAYMENT_CALLBACK)
public class PaymentCallbackStrategy implements LogUpdateStrategy {
    
    @Override
    public void updateLog(CallbackResult result) {
        // 更新支付日志表的逻辑
        System.out.println("更新支付日志表, status: " + result.getStatus());
    }
}

3、使用工厂模式,将匹配的枚举类的值跟handler放到一个map里随后放到内存中【核心】

/**
 * 日志更新策略工厂:负责策略的自动注册和获取
 */
@Component
public class LogUpdateStrategyFactory implements ApplicationContextAware {
    
    private static final Map<CallbackTypeEnum, LogUpdateStrategy> STRATEGY_MAP = new HashMap<>();
    
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) {
        // 获取所有实现了LogUpdateStrategy接口的Bean
        Map<String, LogUpdateStrategy> beans = applicationContext.getBeansOfType(LogUpdateStrategy.class);
        
        beans.forEach((beanName, strategy) -> {
            // 获取策略类上的OrderStrategyType注解
            OrderStrategyType annotation = strategy.getClass().getAnnotation(OrderStrategyType.class);
            if (annotation != null) {
                STRATEGY_MAP.put(annotation.value(), strategy);
            }
        });
    }
    
    /**
     * 根据回调类型获取对应的策略
     */
    public LogUpdateStrategy getStrategy(CallbackTypeEnum type) {
        LogUpdateStrategy strategy = STRATEGY_MAP.get(type);
        if (strategy == null) {
            throw new IllegalArgumentException("未找到对应的日志更新策略: " + type);
        }
        return strategy;
    }
    
    /**
     * 根据类型代码获取策略(便捷方法)
     */
    public LogUpdateStrategy getStrategyByCode(String typeCode) {
        CallbackTypeEnum type = CallbackTypeEnum.getByCode(typeCode);
        return getStrategy(type);
    }
}

4、在使用的过程,只要得到map的key,即可在内存中得到对应的handler


/**
 * 回调日志上下文:对外提供统一入口
 */
@Component
public class CallbackLogContext {
    
    @Autowired
    private LogUpdateStrategyFactory strategyFactory;
    
    /**
     * 处理回调结果
     */
    public void handleCallback(CallbackResult callbackResult) {
        // 1. 从回调结果中获取类型参数
        String interfaceType = callbackResult.getInterfaceType();
        
        // 2. 通过工厂获取对应策略
        LogUpdateStrategy strategy = strategyFactory.getStrategyByCode(interfaceType);
        
        // 3. 执行策略
        strategy.updateLog(callbackResult);
    }
}

5、使用handler对需要处理的业务代码进行处理

/**
 * 订单回调日志更新策略
 */
@Component
@OrderStrategyType(CallbackTypeEnum.ORDER_CALLBACK)
public class OrderCallbackStrategy implements LogUpdateStrategy {
    
    @Autowired
    private OrderLogMapper orderLogMapper; // 假设的订单日志Mapper
    
    @Override
    public void updateLog(CallbackResult result) {
        // 1. 解析回调数据
        String requestId = result.getRequestId();
        String status = result.getStatus();
        
        // 2. 执行更新订单日志表的逻辑
        OrderLog orderLog = new OrderLog();
        orderLog.setRequestId(requestId);
        orderLog.setStatus(status);
        orderLog.setUpdateTime(new Date());
        
        orderLogMapper.updateByRequestId(orderLog);
        System.out.println("更新订单日志表, requestId: " + requestId + ", status: " + status);
    }
}

6、可以进一步将获取handler的过程进一步进行包装,对外只需要使用统一的类调用其的一个方法,就可以对业务代码进行处理

/**
 * 回调接口控制器
 */
@RestController
@RequestMapping("/callback")
public class CallbackController {
    
    @Autowired
    private CallbackLogContext callbackLogContext;
    
    @PostMapping("/notify")
    public String handleCallback(@RequestBody CallbackResult callbackResult) {
        try {
            callbackLogContext.handleCallback(callbackResult);
            return "success";
        } catch (Exception e) {
            return "error: " + e.getMessage();
        }
    }
}