在 Java 中,策略模式的核心是定义算法族、封装算法、动态切换,其实现方式主要围绕 "策略的定义、创建、选择" 展开,根据场景复杂度和技术选型,常见有以下 6 种实现方式,附代码示例和适用场景:
一、基础实现:接口 + 实现类(经典方式)
最标准的实现,通过接口定义策略契约,多个实现类封装不同算法,客户端通过注入或选择不同实现类切换策略。
代码示例
java
// 1. 策略接口(定义契约)
public interface PaymentStrategy {
// 策略核心方法:支付
boolean pay(double amount);
// 获取策略名称
String getStrategyName();
}
// 2. 具体策略1:支付宝支付
public class AlipayStrategy implements PaymentStrategy {
@Override
public boolean pay(double amount) {
System.out.println("使用支付宝支付:" + amount + "元");
return true; // 模拟支付成功
}
@Override
public String getStrategyName() {
return "alipay";
}
}
// 3. 具体策略2:微信支付
public class WechatPayStrategy implements PaymentStrategy {
@Override
public boolean pay(double amount) {
System.out.println("使用微信支付:" + amount + "元");
return true;
}
@Override
public String getStrategyName() {
return "wechat";
}
}
// 4. 策略上下文(封装策略,对外提供统一接口)
public class PaymentContext {
private PaymentStrategy strategy;
// 构造器注入策略
public PaymentContext(PaymentStrategy strategy) {
this.strategy = strategy;
}
// 动态切换策略
public void setStrategy(PaymentStrategy strategy) {
this.strategy = strategy;
}
// 客户端调用入口
public boolean executePayment(double amount) {
return strategy.pay(amount);
}
}
// 5. 客户端使用
public class Client {
public static void main(String[] args) {
// 选择支付宝策略
PaymentContext context = new PaymentContext(new AlipayStrategy());
context.executePayment(100);
// 动态切换为微信策略
context.setStrategy(new WechatPayStrategy());
context.executePayment(200);
}
}
适用场景
- 策略数量固定、变化不频繁(如支付方式、排序算法)。
- 需明确暴露所有策略,允许客户端直接选择。
二、枚举实现(简化策略管理)
用枚举封装所有策略,利用枚举的 "单例特性" 和 "天然分组" 优势,减少类冗余,简化策略选择。
代码示例
java
// 1. 枚举策略(实现策略逻辑)
public enum PaymentStrategyEnum {
// 支付宝策略
ALIPAY {
@Override
public boolean pay(double amount) {
System.out.println("枚举-支付宝支付:" + amount + "元");
return true;
}
},
// 微信支付策略
WECHAT {
@Override
public boolean pay(double amount) {
System.out.println("枚举-微信支付:" + amount + "元");
return true;
}
};
// 策略核心方法(枚举抽象方法)
public abstract boolean pay(double amount);
}
// 2. 客户端使用(直接通过枚举选择策略)
public class Client {
public static void main(String[] args) {
// 根据枚举值选择策略
PaymentStrategyEnum.ALIPAY.pay(100);
PaymentStrategyEnum.WECHAT.pay(200);
// 支持动态传入策略(如从配置文件读取)
String strategyName = "ALIPAY"; // 可来自配置
PaymentStrategyEnum strategy = Enum.valueOf(PaymentStrategyEnum.class, strategyName);
strategy.pay(300);
}
}
适用场景
- 策略数量少、逻辑简单(如状态判断、固定规则)。
- 无需动态扩展策略(枚举不可动态新增)。
三、工厂模式 + 策略模式(解耦策略创建)
通过工厂类封装策略的创建逻辑,客户端无需关注策略的实例化细节,只需传入标识即可获取对应策略,适合策略较多的场景。
代码示例
java
// 1. 策略接口(同基础实现)
public interface PaymentStrategy {
boolean pay(double amount);
String getStrategyCode();
}
// 2. 具体策略(同基础实现:AlipayStrategy、WechatPayStrategy)
// 3. 策略工厂(封装策略创建)
public class PaymentStrategyFactory {
// 缓存策略实例(单例)
private static final Map<String, PaymentStrategy> STRATEGY_MAP = new HashMap<>();
// 静态初始化:注册所有策略
static {
STRATEGY_MAP.put("alipay", new AlipayStrategy());
STRATEGY_MAP.put("wechat", new WechatPayStrategy());
}
// 禁止外部实例化
private PaymentStrategyFactory() {}
// 根据标识获取策略
public static PaymentStrategy getStrategy(String strategyCode) {
PaymentStrategy strategy = STRATEGY_MAP.get(strategyCode);
if (strategy == null) {
throw new IllegalArgumentException("不支持的支付方式:" + strategyCode);
}
return strategy;
}
// 扩展:动态注册新策略(支持热更新)
public static void registerStrategy(String code, PaymentStrategy strategy) {
STRATEGY_MAP.put(code, strategy);
}
}
// 4. 客户端使用
public class Client {
public static void main(String[] args) {
// 从工厂获取策略(无需手动new)
PaymentStrategy alipay = PaymentStrategyFactory.getStrategy("alipay");
alipay.pay(100);
PaymentStrategy wechat = PaymentStrategyFactory.getStrategy("wechat");
wechat.pay(200);
// 动态注册新策略(如新增银联支付)
PaymentStrategyFactory.registerStrategy("unionpay", new UnionPayStrategy());
PaymentStrategyFactory.getStrategy("unionpay").pay(300);
}
}
// 新增策略:银联支付(无需修改工厂核心逻辑)
class UnionPayStrategy implements PaymentStrategy {
@Override
public boolean pay(double amount) {
System.out.println("使用银联支付:" + amount + "元");
return true;
}
@Override
public String getStrategyCode() {
return "unionpay";
}
}
适用场景
- 策略数量多(如 10+),需要统一管理创建逻辑。
- 客户端只需通过标识(如字符串、枚举)选择策略,无需关注实现。
四、注解 + 反射(动态扫描策略)
通过自定义注解标记策略类,程序启动时扫描所有带注解的策略并注册到工厂,支持 "无侵入式扩展"(新增策略无需修改工厂代码)。
代码示例
java
// 1. 自定义策略注解(标记策略标识)
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface PaymentStrategyAnnotation {
String code(); // 策略唯一标识
}
// 2. 策略接口(同基础实现)
public interface PaymentStrategy {
boolean pay(double amount);
}
// 3. 具体策略(用注解标记)
@PaymentStrategyAnnotation(code = "alipay")
public class AlipayStrategy implements PaymentStrategy {
@Override
public boolean pay(double amount) {
System.out.println("注解-支付宝支付:" + amount + "元");
return true;
}
}
@PaymentStrategyAnnotation(code = "wechat")
public class WechatPayStrategy implements PaymentStrategy {
@Override
public boolean pay(double amount) {
System.out.println("注解-微信支付:" + amount + "元");
return true;
}
}
// 4. 策略工厂(反射扫描注解策略)
public class AnnotationStrategyFactory {
private static final Map<String, PaymentStrategy> STRATEGY_MAP = new HashMap<>();
// 初始化:扫描指定包下的所有策略
static {
try {
// 扫描com.example.strategy包下的所有类
Reflections reflections = new Reflections("com.example.strategy");
// 获取所有带@PaymentStrategyAnnotation注解的类
Set<Class<?>> strategyClasses = reflections.getTypesAnnotatedWith(PaymentStrategyAnnotation.class);
// 实例化并注册策略
for (Class<?> clazz : strategyClasses) {
PaymentStrategyAnnotation annotation = clazz.getAnnotation(PaymentStrategyAnnotation.class);
String code = annotation.code();
PaymentStrategy strategy = (PaymentStrategy) clazz.newInstance();
STRATEGY_MAP.put(code, strategy);
}
} catch (Exception e) {
throw new RuntimeException("策略初始化失败", e);
}
}
// 获取策略
public static PaymentStrategy getStrategy(String code) {
return STRATEGY_MAP.getOrDefault(code, () -> {
System.out.println("默认策略:支付失败");
return false;
});
}
}
// 5. 客户端使用(依赖Reflections库,需导入依赖)
public class Client {
public static void main(String[] args) {
AnnotationStrategyFactory.getStrategy("alipay").pay(100);
AnnotationStrategyFactory.getStrategy("wechat").pay(200);
}
}
依赖说明
需导入反射扫描库(Maven):
XML
<dependency>
<groupId>org.reflections</groupId>
<artifactId>reflections</artifactId>
<version>0.10.2</version>
</dependency>
适用场景
- 大型项目,策略频繁新增(如插件化架构)。
- 追求 "开闭原则",新增策略无需修改现有代码。
五、Lambda 表达式(简化无状态策略)
对于无状态、逻辑简单的策略,可直接用 Lambda 表达式实现策略接口,无需创建单独的实现类,简化代码。
代码示例
java
// 1. 函数式策略接口(仅含一个抽象方法)
@FunctionalInterface
public interface PaymentStrategy {
boolean pay(double amount);
}
// 2. 策略上下文(同基础实现)
public class PaymentContext {
private PaymentStrategy strategy;
public PaymentContext(PaymentStrategy strategy) {
this.strategy = strategy;
}
public boolean execute(double amount) {
return strategy.pay(amount);
}
}
// 3. 客户端使用(Lambda直接实现策略)
public class Client {
public static void main(String[] args) {
// Lambda实现支付宝策略
PaymentContext alipayContext = new PaymentContext(amount -> {
System.out.println("Lambda-支付宝支付:" + amount + "元");
return true;
});
alipayContext.execute(100);
// Lambda实现微信策略
PaymentContext wechatContext = new PaymentContext(amount -> {
System.out.println("Lambda-微信支付:" + amount + "元");
return true;
});
wechatContext.execute(200);
// 甚至可以直接传递Lambda,无需上下文
PaymentStrategy unionPay = amount -> {
System.out.println("Lambda-银联支付:" + amount + "元");
return true;
};
unionPay.pay(300);
}
}
适用场景
- 策略逻辑简单(1-3 行代码)、无状态(无需成员变量)。
- 临时策略(仅使用一次),无需复用。
六、Spring 容器整合(依赖注入 + 自动装配)
在 Spring 项目中,利用 Spring 的 IOC 容器管理策略实例,通过@Autowired自动注入所有策略,结合Map或List实现策略选择,无需手动创建工厂。
代码示例
java
// 1. 策略接口(同基础实现)
public interface PaymentStrategy {
boolean pay(double amount);
String getStrategyCode();
}
// 2. 具体策略(Spring组件)
@Component // 交给Spring管理
public class AlipayStrategy implements PaymentStrategy {
@Override
public boolean pay(double amount) {
System.out.println("Spring-支付宝支付:" + amount + "元");
return true;
}
@Override
public String getStrategyCode() {
return "alipay";
}
}
@Component
public class WechatPayStrategy implements PaymentStrategy {
@Override
public boolean pay(double amount) {
System.out.println("Spring-微信支付:" + amount + "元");
return true;
}
@Override
public String getStrategyCode() {
return "wechat";
}
}
// 3. 策略服务(Spring组件,自动注入所有策略)
@Service
public class PaymentService {
// Spring会自动将所有PaymentStrategy实现类注入到Map中:key=beanName,value=策略实例
@Autowired
private Map<String, PaymentStrategy> strategyMap;
// 或按策略code映射(自定义key)
private Map<String, PaymentStrategy> codeToStrategyMap;
// 初始化:将策略按code分组
@PostConstruct
public void init() {
codeToStrategyMap = strategyMap.values().stream()
.collect(Collectors.toMap(PaymentStrategy::getStrategyCode, s -> s));
}
// 执行策略
public boolean executePayment(String strategyCode, double amount) {
PaymentStrategy strategy = codeToStrategyMap.get(strategyCode);
if (strategy == null) {
throw new IllegalArgumentException("不支持的支付方式");
}
return strategy.pay(amount);
}
}
// 4. 客户端使用(Spring环境)
@SpringBootApplication
public class StrategyApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(StrategyApplication.class, args);
PaymentService paymentService = context.getBean(PaymentService.class);
paymentService.executePayment("alipay", 100);
paymentService.executePayment("wechat", 200);
}
}
适用场景
- Spring Boot/Spring MVC 项目(充分利用 Spring 的 IOC 特性)。
- 策略需要依赖其他 Spring 组件(如
@Autowired数据源、缓存等)。
六种实现方式对比
| 实现方式 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 接口 + 实现类(经典) | 结构清晰、易理解 | 策略多时有类爆炸问题 | 策略少、变化不频繁 |
| 枚举实现 | 代码简洁、无类冗余 | 策略逻辑复杂时不适用,不可动态扩展 | 策略少、逻辑简单 |
| 工厂 + 策略 | 解耦创建逻辑、支持动态扩展 | 新增策略需修改工厂注册代码 | 策略较多、需要统一管理 |
| 注解 + 反射 | 无侵入扩展、支持插件化 | 依赖反射库、初始化开销略大 | 大型项目、策略频繁新增 |
| Lambda 表达式 | 代码极简、无需创建类 | 无状态、逻辑简单场景受限 | 临时策略、简单逻辑 |
| Spring 整合 | 自动注入、支持依赖管理 | 依赖 Spring 环境 | Spring 项目、策略需依赖其他组件 |
核心设计原则
无论哪种实现方式,都需遵循:
- 开闭原则:新增策略无需修改现有代码(枚举方式除外)。
- 单一职责:每个策略只负责一种算法,上下文只负责协调策略。
- 里氏替换:任何策略都可替换为其他实现,不影响客户端使用。