策略模式:Spring Bean策略与枚举 Lambda策略

1-使用目的:

  • 替换大量的 if-else 或 switch-case 语句,让代码更简洁易读
  • 新增推送类型时只需添加新的策略实现,不需要修改现有业务逻辑,便于维护

2-两种常见的策略模式

2-1.Spring Bean策略模式

定义枚举:用于管理推送的类型,主要是维护一个字典,还有个好处就是枚举天然的编译期检查,出现问题会直接飘红的,必须修改了才能启动

java 复制代码
@Getter
@AllArgsConstructor
public enum DataPushType {

    ORDER_CREATE(1, "订单创建推送"),
    ORDER_CANCEL(2, "订单取消推送"),
    ORDER_FINISH(3, "订单完成推送");

    private final int code;
    
    private final String desc;

    public static DataPushType of(int code) {
        for (DataPushType type : values()) {
            if (type.code == code) {
                return type;
            }
        }
        throw new IllegalArgumentException("未知推送类型: " + code);
    }
}

策略注册接口:后续的具体实现类,都要实现这个接口

java 复制代码
public interface DataPushStrategy {

    /**
     * 当前策略支持的推送类型
     */
    DataPushType getType();

    /**
     * 处理推送数据
     */
    void handlePushData(String data);
}

策略具体实现:以OrderCreate示例

java 复制代码
// OrderCreate示例
@Component
@Slf4j
public class OrderCreatePushStrategy implements DataPushStrategy {

    @Override
    public DataPushType getType() {
        return DataPushType.ORDER_CREATE;
    }

    @Override
    public void handlePushData(String data) {
        log.info("处理【订单创建】推送,data={}", data);
        // 具体业务逻辑
    }
}

策略manager:用于注册和管理策略,具体使用的就是这个类,外部注入这个策略manager Bean,使用对应方法即可

java 复制代码
@Component
@Slf4j
public class DataPushStrategyManager {

    private final Map<DataPushType, DataPushStrategy> strategyMap =
            new EnumMap<>(DataPushType.class);

    // 构造函数,Spring会注入所有实现DataPushStrategy的实现类
    public DataPushStrategyManager(List<DataPushStrategy> strategies) {

        for (DataPushStrategy strategy : strategies) {
            DataPushType type = strategy.getType();

            if (strategyMap.containsKey(type)) {
                throw new IllegalStateException("重复的推送策略定义: " + type);
            }
            // 放入策略map中
            strategyMap.put(type, strategy);
            log.info("注册推送策略: type={}, class={}", type, strategy.getClass().getSimpleName());
        }
    }

    // 通过策略typecode,来执行对应的策略
    public void execute(int typeCode, String data) {
        DataPushType type = DataPushType.of(typeCode);
        execute(type, data);
    }

    // 通过DataPushType,来执行对应的策略
    public void execute(DataPushType type, String data) {
        DataPushStrategy strategy = strategyMap.get(type);
        if (strategy == null) {
            throw new IllegalArgumentException(
                    "未找到推送策略: " + type);
        }
        strategy.handlePushData(data);
    }
}

调用:

bash 复制代码
1.注入strategyManager Bean
2.直接调用strategyManager.execute(typeCode, data);

2-2.枚举策略模式

定义枚举:相比以前的那个就是加了一个参数,主要是根据对应的类型,然后该调用Bean里的哪个方法

java 复制代码
@Getter
@AllArgsConstructor
public enum DataPushStrategyEnum {

    ORDER_CREATE(1, "订单创建推送", (data, service) -> service.handleOrderCreate(data)),

    ORDER_CANCEL(2, "订单取消推送", (data, service) -> service.handleOrderCancel(data)),

    ORDER_FINISH(3, "订单完成推送", (data, service) -> service.handleOrderFinish(data));

    private final int code;

    private final String desc;

    /**
     * 具体执行逻辑(策略)
     */
    private final BiConsumer<String, DataPushService> executor;

    private static final Map<Integer, DataPushStrategyEnum> CACHE =
            Arrays.stream(values())
                    .collect(Collectors.toMap(DataPushStrategyEnum::getCode, v -> v));

    public static DataPushStrategyEnum of(int code) {
        DataPushStrategyEnum strategy = CACHE.get(code);
        if (strategy == null) {
            throw new IllegalArgumentException("不支持的推送类型: " + code);
        }
        return strategy;
    }

    public void execute(String data, DataPushService service) {
        executor.accept(data, service);
    }
}

主要的Bean:具体的业务实现

java 复制代码
@Service
@Slf4j
public class DataPushService {

    public void handleOrderCreate(String data) {
        log.info("处理【订单创建】推送,data={}", data);
        // 原 OrderCreatePushStrategy 的逻辑
    }

    public void handleOrderCancel(String data) {
        log.info("处理【订单取消】推送,data={}", data);
        // 原 OrderCancelPushStrategy 的逻辑
    }

    public void handleOrderFinish(String data) {
        log.info("处理【订单完成】推送,data={}", data);
        // 原 OrderFinishPushStrategy 的逻辑
    }
}

构建调用层:再包一层,外部注入这个Bean去调用

java 复制代码
@Service
public class DataPushFacade {

    private final DataPushService dataPushService;
	// spring构造时会自动的注入dataPushService
    public DataPushFacade(DataPushService dataPushService) {
        this.dataPushService = dataPushService;
    }

    public void push(int typeCode, String data) {
        DataPushStrategyEnum.of(typeCode)
                .execute(data, dataPushService);
    }
}

这种只适合业务不复杂的简单情况,一旦业务复杂,需要需要注入多个依赖,频繁修改的业务,就不要用这个了,还是用传统的Spring Bean方式

PS:

bash 复制代码
(data, service) -> service.handleOrderFinish(data)
#是一个实现了 BiConsumer<String, DataPushService> 的 Lambda 表达式实例

从 Java 语义上讲:

复制代码
BiConsumer<String, DataPushService> executor =
        (data, service) -> service.handleOrderFinish(data);

等价于(概念等价,不是字节码等价):

java 复制代码
BiConsumer<String, DataPushService> executor =
    new BiConsumer<String, DataPushService>() {
    @Override
    public void accept(String data, DataPushService service) {
        service.handleOrderFinish(data);
    }
};

只是Java 8之后,用Lambda语法糖写出来的

相关推荐
亓才孓1 分钟前
[JDBC]批处理
java
春日见2 分钟前
车辆动力学:前后轮车轴
java·开发语言·驱动开发·docker·计算机外设
宋小黑15 分钟前
JDK 6到25 全版本网盘合集 (Windows + Mac + Linux)
java·后端
7哥♡ۣۖᝰꫛꫀꪝۣℋ26 分钟前
Spring-cloud\Eureka
java·spring·微服务·eureka
老毛肚39 分钟前
手写mybatis
java·数据库·mybatis
两点王爷41 分钟前
Java基础面试题——【Java语言特性】
java·开发语言
choke2331 小时前
[特殊字符] Python 文件与路径操作
java·前端·javascript
choke2331 小时前
Python 基础语法精讲:数据类型、运算符与输入输出
java·linux·服务器
岁岁种桃花儿1 小时前
CentOS7 彻底卸载所有JDK/JRE + 重新安装JDK8(实操完整版,解决kafka/jps报错)
java·开发语言·kafka
一灰灰blog1 小时前
Spring AI中的多轮对话艺术:让大模型主动提问获取明确需求
数据库·人工智能·spring