策略模式: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语法糖写出来的

相关推荐
LiRuiJie2 小时前
从OS层面深入剖析JVM如何实现多线程与同步互斥
java·jvm·os·底层
m0_719084112 小时前
滴滴滴滴滴
java·开发语言
玖釉-2 小时前
[Vulkan 学习之路] 29 - 加载模型 (Loading Models)
c++·windows·图形渲染
张乔242 小时前
spring boot项目中设置默认的方法实现
java·数据库·spring boot
小北方城市网2 小时前
SpringBoot 集成 Redis 实战(缓存与分布式锁):提升系统性能与并发能力
spring boot·python·rabbitmq·java-rabbitmq·数据库架构
heartbeat..2 小时前
数据库性能优化:SQL 语句的优化(原理+解析+面试)
java·数据库·sql·性能优化
韩立学长2 小时前
基于Springboot琴行学生课程信息管理系统2gt392wb(程序、源码、数据库、调试部署方案及开发环境)系统界面展示及获取方式置于文档末尾,可供参考。
数据库·spring boot·后端
逐浪CMS发哥2 小时前
windows删除字体缓存(即删除用户目录下的字体文件)
windows·缓存
Qhumaing2 小时前
Java学习——第五章 异常处理与输入输出流笔记
java·笔记·学习