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语法糖写出来的