一、使用背景
在公司进行业务开发中,随着业务的复杂性不断提升,开发者常常需要为不同的业务场景设计不同的策略。传统的做法往往依赖于条件判断或大量的 if-else 语句来实现策略的切换。为了更好地解决这些问题,策略模式应运而生。策略模式允许定义一系列算法,将每个算法封装起来,并使它们可以互换。
在 Java 中,策略模式的实现有许多种方式,其中使用函数式编程特性来实现更加灵活的策略模式,是一种非常高效且现代的做法。本文将对一个基于 Java 函数式编程的策略工具类 BizStrategy
进行分析,探讨其设计原理和实际应用。
二、策略模式对比
2.1 使用传统策略模式
在没有 BizStrategy
工具类之前,策略模式的实现可能会像这样:
// 传统的策略接口
interface Strategy {
String execute(String context);
}
// 策略A
class StrategyA implements Strategy {
@Override
public String execute(String context) {
return "策略A执行结果:" + context;
}
}
// 策略B
class StrategyB implements Strategy {
@Override
public String execute(String context) {
return "策略B执行结果:" + context;
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
String strategyType = "A"; // 假设选择了策略A
String context = "上下文";
Strategy strategy;
if ("A".equals(strategyType)) {
strategy = new StrategyA();
} else if ("B".equals(strategyType)) {
strategy = new StrategyB();
} else {
throw new IllegalArgumentException("没有找到对应的策略:" + strategyType);
}
System.out.println(strategy.execute(context));
}
}
在这个传统的实现中,我们需要通过大量的条件判断来选择不同的策略。每次添加一个新的策略,都需要修改客户端代码,维护起来非常繁琐,且代码重复度高。
2.2 使用业务策略工具
使用 BizStrategy
工具类后,代码变得更加简洁,策略的注册和执行也变得更加灵活。
public class Client {
public static void main(String[] args) {
// 创建策略工具类实例
BizStrategy<String, String, String> strategy = new BizStrategy<>();
// 注册策略
strategy.registerFunction("A", context -> "策略A执行结果:" + context);
strategy.registerFunction("B", context -> "策略B执行结果:" + context);
// 执行策略
String context = "上下文";
System.out.println(strategy.execute("A", context)); // 输出: 策略A执行结果:上下文
System.out.println(strategy.executeOrDefault("BB", context, ctx -> "默认策略执行结果:" + ctx)); // 输出: 默认策略执行结果:上下文
}
}
在这个实现中,我们通过 BizStrategy
类注册了策略A和策略B,并直接通过 execute
方法执行策略。即使没有找到对应的策略,executeOrDefault
方法也可以提供默认策略,避免了大量的条件判断。新增策略时,只需要注册新的策略,不需要修改现有代码。
三、介绍业务策略
3.1 使用步骤
1.注册策略:BizStrategy
可以非常灵活地注册不同类型的策略。此外,registerIf
方法提供了条件注册策略的能力,只有在条件满足时才会注册对应的策略。
strategy.registerFunction("A", context -> "策略A执行结果:" + context);
strategy.registerFunction("B", context -> "策略B执行结果:" + context);
2.执行策略: 执行策略时,BizStrategy
提供了多个重载的 execute
方法,可以根据策略的不同参数类型来选择适当的执行方式。
String context = "上下文";
System.out.println(strategy.execute("A", context)); // 输出: 策略A执行结果:上下文
3.2 支持的注册策略类型
BizStrategy
通过不同的函数接口来支持多种策略类型,具体包括:
- Function:接受一个参数并返回结果的策略。
- Runnable:无参数且无返回值的策略。
- Consumer:接受一个参数但没有返回值的策略。
- Supplier:无参数且有返回值的策略。
- Predicate:接受一个参数并返回布尔值的策略。
四、文章总结
BizStrategy
工具类提供了一个现代化的、基于 Java 函数式编程的策略管理方案。通过对策略的灵活注册与执行,它使得策略模式在实际应用中更加简洁、高效,并且具备很好的扩展性。相比传统的策略模式实现,BizStrategy
更加灵活,能够动态注册策略、条件注册策略,并支持多种类型的策略。
五、附上代码
/**
* @author: bdmcom
* @createTime: 2024/12/14 20:39
* @company: <a href="https://www.bdmcom.cn">本当迷博客</a>
* @description: 策略工具类
*/
@Slf4j
public class BizStrategy<T, P, R> {
public static final String STRATEGY_NOT_FOUND = "没有找到对应的策略:";
private final ConcurrentMap<T, Function<P, R>> strategies = new ConcurrentHashMap<>();
/**
* 注册一个策略(Function 类型)
*/
public void registerFunction(T key, Function<P, R> action) {
strategies.put(key, action);
}
/**
* 注册一个策略(Runnable 类型,接受无参数但没有返回值)
*/
public void registerRunnable(T key, Runnable action) {
strategies.put(key, context -> {
action.run();
return null; // 返回null,表示没有返回值
});
}
/**
* 注册一个策略(Consumer 类型,接受一个参数但没有返回值)
*/
public void registerConsumer(T key, Consumer<P> action) {
strategies.put(key, t -> {
action.accept(t);
return null;
});
}
/**
* 注册一个策略(Supplier 类型,接受无参数并返回结果)
*/
public void registerSupplier(T key, Supplier<R> action) {
strategies.put(key, t -> action.get());
}
/**
* 注册一个策略(Predicate 类型,接受一个参数并返回布尔值)
*/
@SuppressWarnings("all")
public void registerPredicate(T key, Predicate<P> action) {
strategies.put(key, t -> action.test(t) ? (R) Boolean.TRUE : (R) Boolean.FALSE);
}
/**
* 执行策略(无参数策略)
*/
public void execute(T key) {
Optional.ofNullable(strategies.get(key))
.orElseThrow(() -> new IllegalArgumentException(STRATEGY_NOT_FOUND + key))
.apply(null);
}
/**
* 执行无参数的 Supplier 类型策略
*/
public R executeSupplier(T key) {
return Optional.ofNullable(strategies.get(key))
.orElseThrow(() -> new IllegalArgumentException(STRATEGY_NOT_FOUND + key))
.apply(null);
}
/**
* 执行策略(有参数的策略)
*
* @param key 策略键
* @param context 上下文
* @return 策略返回的结果
*/
public R execute(T key, P context) {
return Optional.ofNullable(strategies.get(key))
.orElseThrow(() -> new IllegalArgumentException(STRATEGY_NOT_FOUND + key))
.apply(context);
}
/**
* 执行策略,如果没有找到对应的策略则执行默认操作
*
* @param key 策略键
* @param context 上下文
* @param defaultAction 默认操作
* @return 策略返回的结果
*/
public R executeOrDefault(T key, P context, Function<P, R> defaultAction) {
return strategies.getOrDefault(key, defaultAction).apply(context);
}
/**
* 根据条件动态注册策略
*
* @param condition 注册条件
* @param key 策略键
* @param action 策略逻辑
*/
public void registerIf(Predicate<T> condition, T key, Function<P, R> action) {
if (condition.test(key)) {
registerFunction(key, action);
}
}
/**
* 清除所有注册的策略
*/
public void clearStrategies() {
strategies.clear();
}
/**
* 移除特定的策略
*
* @param key 策略键
*/
public void removeStrategy(T key) {
strategies.remove(key);
}
@SuppressWarnings("all")
public static void main(String[] args) {
log.info("-----------------------策略工具类测试(1入参,1回值)-------------------------------------------------------------");
// 开始注册策略
BizStrategy<String, String, String> strategy = new BizStrategy<>();
strategy.registerFunction("A", context -> "策略A执行结果:" + context);
strategy.registerFunction("B", context -> "策略B执行结果:" + context);
strategy.registerFunction("C", context -> "策略C执行结果:" + context);
strategy.registerIf("D"::equals, "D", context -> "策略D执行结果" + context);
strategy.registerIf("E"::equals, "E", context -> "策略E执行结果" + context);
// 执行策略
log.info(strategy.execute("A", "上下文"));
log.info(strategy.executeOrDefault("BB", "上下文", context -> "默认策略执行结果:" + context));
/*// 移除策略
strategy.removeStrategy("A");
log.info(strategy.execute("A", "上下文"));
// 清除所有策略
strategy.clearStrategies();
log.info(strategy.execute("B", "上下文"));*/
log.info("-------------------------------------------------------------------------------------------------");
log.info("-----------------------策略工具类测试(0入参,0回值)-------------------------------------------------------------");
// 开始注册策略
BizStrategy<String, Void, Void> strategy2 = new BizStrategy<>();
strategy2.registerRunnable("A", () -> log.info("策略A执行结果"));
strategy2.registerRunnable("B", () -> log.info("策略B执行结果"));
// 执行策略
strategy2.execute("A");
strategy2.execute("B");
log.info("-------------------------------------------------------------------------------------------------");
log.info("-----------------------策略工具类测试(1入参,0回值)-------------------------------------------------------------");
// 开始注册策略
BizStrategy<String, String, Void> strategy3 = new BizStrategy<>();
strategy3.registerConsumer("A", context -> log.info("策略A执行结果:" + context));
strategy3.registerConsumer("B", context -> log.info("策略B执行结果:" + context));
// 执行策略
strategy3.execute("A", "上下文");
strategy3.execute("B", "上下文");
log.info("-------------------------------------------------------------------------------------------------");
log.info("-----------------------策略工具类测试(0入参,1回值)-------------------------------------------------------------");
// 开始注册策略
BizStrategy<String, Void, String> strategy4 = new BizStrategy<>();
strategy4.registerSupplier("A", () -> "策略A执行结果");
strategy4.registerSupplier("B", () -> "策略B执行结果");
// 执行策略
log.info(strategy4.executeSupplier("A"));
}
}