JAVA中六种策略模式的实现
在 Java 中,策略模式的核心是定义算法族、封装算法、动态切换,其实现方式主要围绕 “策略的定义、创建、选择” 展开,根据场景复杂度和技术选型,常见有以下 6 种实现方式,附代码示例和适用场景:
一、基础实现:接口 + 实现类(经典方式)
最标准的实现,通过接口定义策略契约,多个实现类封装不同算法,客户端通过注入或选择不同实现类切换策略。
代码示例
// 1. 策略接口(定义契约)
public interface PaymentStrategy {// 策略核心方法:支付boolean pay(double amount);// 获取策略名称String getStrategyName();
}// 2. 具体策略1:支付宝支付
public class AlipayStrategy implements PaymentStrategy {@Overridepublic boolean pay(double amount) {System.out.println("使用支付宝支付:" + amount + "元");return true; // 模拟支付成功}@Overridepublic String getStrategyName() {return "alipay";}
}// 3. 具体策略2:微信支付
public class WechatPayStrategy implements PaymentStrategy {@Overridepublic boolean pay(double amount) {System.out.println("使用微信支付:" + amount + "元");return true;}@Overridepublic 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);}
}
适用场景
- 策略数量固定、变化不频繁(如支付方式、排序算法)。
- 需明确暴露所有策略,允许客户端直接选择。
二、枚举实现(简化策略管理)
用枚举封装所有策略,利用枚举的 “单例特性” 和 “天然分组” 优势,减少类冗余,简化策略选择。
代码示例
// 1. 枚举策略(实现策略逻辑)
public enum PaymentStrategyEnum {// 支付宝策略ALIPAY {@Overridepublic boolean pay(double amount) {System.out.println("枚举-支付宝支付:" + amount + "元");return true;}},// 微信支付策略WECHAT {@Overridepublic 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);}
}
适用场景
- 策略数量少、逻辑简单(如状态判断、固定规则)。
- 无需动态扩展策略(枚举不可动态新增)。
三、工厂模式 + 策略模式(解耦策略创建)
通过工厂类封装策略的创建逻辑,客户端无需关注策略的实例化细节,只需传入标识即可获取对应策略,适合策略较多的场景。
代码示例
// 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 {@Overridepublic boolean pay(double amount) {System.out.println("使用银联支付:" + amount + "元");return true;}@Overridepublic String getStrategyCode() {return "unionpay";}
}
适用场景
- 策略数量多(如 10+),需要统一管理创建逻辑。
- 客户端只需通过标识(如字符串、枚举)选择策略,无需关注实现。
四、注解 + 反射(动态扫描策略)
通过自定义注解标记策略类,程序启动时扫描所有带注解的策略并注册到工厂,支持 “无侵入式扩展”(新增策略无需修改工厂代码)。
代码示例
// 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 {@Overridepublic boolean pay(double amount) {System.out.println("注解-支付宝支付:" + amount + "元");return true;}
}@PaymentStrategyAnnotation(code = "wechat")
public class WechatPayStrategy implements PaymentStrategy {@Overridepublic 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):
<dependency><groupId>org.reflections</groupId><artifactId>reflections</artifactId><version>0.10.2</version>
</dependency>
适用场景
- 大型项目,策略频繁新增(如插件化架构)。
- 追求 “开闭原则”,新增策略无需修改现有代码。
五、Lambda 表达式(简化无状态策略)
对于无状态、逻辑简单的策略,可直接用 Lambda 表达式实现策略接口,无需创建单独的实现类,简化代码。
代码示例
// 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实现策略选择,无需手动创建工厂。
代码示例
// 1. 策略接口(同基础实现)
public interface PaymentStrategy {boolean pay(double amount);String getStrategyCode();
}// 2. 具体策略(Spring组件)
@Component // 交给Spring管理
public class AlipayStrategy implements PaymentStrategy {@Overridepublic boolean pay(double amount) {System.out.println("Spring-支付宝支付:" + amount + "元");return true;}@Overridepublic String getStrategyCode() {return "alipay";}
}@Component
public class WechatPayStrategy implements PaymentStrategy {@Overridepublic boolean pay(double amount) {System.out.println("Spring-微信支付:" + amount + "元");return true;}@Overridepublic String getStrategyCode() {return "wechat";}
}// 3. 策略服务(Spring组件,自动注入所有策略)
@Service
public class PaymentService {// Spring会自动将所有PaymentStrategy实现类注入到Map中:key=beanName,value=策略实例@Autowiredprivate Map<String, PaymentStrategy> strategyMap;// 或按策略code映射(自定义key)private Map<String, PaymentStrategy> codeToStrategyMap;// 初始化:将策略按code分组@PostConstructpublic 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 项目、策略需依赖其他组件 |
核心设计原则
无论哪种实现方式,都需遵循:
- 开闭原则:新增策略无需修改现有代码(枚举方式除外)。
- 单一职责:每个策略只负责一种算法,上下文只负责协调策略。
- 里氏替换:任何策略都可替换为其他实现,不影响客户端使用。
