策略模式深度分析
目录
策略模式概述
策略模式(Strategy Pattern)是一种行为型设计模式,属于GoF 23种设计模式之一。它定义了一系列算法,将每个算法封装起来,并使它们可以相互替换。策略模式让算法的变化独立于使用算法的客户端。
核心组件
- Strategy(策略接口):定义所有具体策略的公共接口
- ConcreteStrategy(具体策略):实现策略接口的具体算法
- Context(上下文):持有一个策略对象的引用,并调用策略对象的方法
设计原则
- 开闭原则:对扩展开放,对修改关闭
- 单一职责原则:每个策略类只负责一种算法
- 依赖倒置原则:依赖抽象而不是具体实现
实际应用场景
1. 支付系统
java
// 支付策略接口
public interface PaymentStrategy {
void pay(BigDecimal amount);
}
// 支付宝支付策略
public class AlipayStrategy implements PaymentStrategy {
@Override
public void pay(BigDecimal amount) {
System.out.println("使用支付宝支付:" + amount);
}
}
// 微信支付策略
public class WechatPayStrategy implements PaymentStrategy {
@Override
public void pay(BigDecimal amount) {
System.out.println("使用微信支付:" + amount);
}
}
// 支付上下文
public class PaymentContext {
private PaymentStrategy strategy;
public void setStrategy(PaymentStrategy strategy) {
this.strategy = strategy;
}
public void executePayment(BigDecimal amount) {
strategy.pay(amount);
}
}
2. 数据压缩系统
java
// 压缩策略接口
public interface CompressionStrategy {
byte[] compress(byte[] data);
byte[] decompress(byte[] compressedData);
}
// ZIP压缩策略
public class ZipCompressionStrategy implements CompressionStrategy {
@Override
public byte[] compress(byte[] data) {
// ZIP压缩实现
return zipCompress(data);
}
@Override
public byte[] decompress(byte[] compressedData) {
// ZIP解压实现
return zipDecompress(compressedData);
}
}
// GZIP压缩策略
public class GzipCompressionStrategy implements CompressionStrategy {
@Override
public byte[] compress(byte[] data) {
// GZIP压缩实现
return gzipCompress(data);
}
@Override
public byte[] decompress(byte[] compressedData) {
// GZIP解压实现
return gzipDecompress(compressedData);
}
}
3. 日志记录系统
java
// 日志策略接口
public interface LoggingStrategy {
void log(String message, LogLevel level);
}
// 文件日志策略
public class FileLoggingStrategy implements LoggingStrategy {
@Override
public void log(String message, LogLevel level) {
// 写入文件
writeToFile(message, level);
}
}
// 数据库日志策略
public class DatabaseLoggingStrategy implements LoggingStrategy {
@Override
public void log(String message, LogLevel level) {
// 写入数据库
writeToDatabase(message, level);
}
}
// 控制台日志策略
public class ConsoleLoggingStrategy implements LoggingStrategy {
@Override
public void log(String message, LogLevel level) {
// 输出到控制台
System.out.println(level + ": " + message);
}
}
4. 排序算法选择
java
// 排序策略接口
public interface SortStrategy {
void sort(int[] array);
}
// 快速排序策略
public class QuickSortStrategy implements SortStrategy {
@Override
public void sort(int[] array) {
// 快速排序实现
quickSort(array, 0, array.length - 1);
}
}
// 归并排序策略
public class MergeSortStrategy implements SortStrategy {
@Override
public void sort(int[] array) {
// 归并排序实现
mergeSort(array, 0, array.length - 1);
}
}
// 堆排序策略
public class HeapSortStrategy implements SortStrategy {
@Override
public void sort(int[] array) {
// 堆排序实现
heapSort(array);
}
}
5. 数据验证系统
java
// 验证策略接口
public interface ValidationStrategy {
boolean validate(String data);
}
// 邮箱验证策略
public class EmailValidationStrategy implements ValidationStrategy {
@Override
public boolean validate(String data) {
return data.matches("^[A-Za-z0-9+_.-]+@(.+)$");
}
}
// 手机号验证策略
public class PhoneValidationStrategy implements ValidationStrategy {
@Override
public boolean validate(String data) {
return data.matches("^1[3-9]\\d{9}$");
}
}
// 身份证验证策略
public class IdCardValidationStrategy implements ValidationStrategy {
@Override
public boolean validate(String data) {
return data.matches("^\\d{17}[\\dXx]$");
}
}
重难点分析
1. 策略选择机制设计
难点
- 如何根据运行时条件动态选择合适的策略
- 避免硬编码策略选择逻辑
- 支持策略的优先级和回退机制
解决方案
java
// 策略选择器接口
public interface StrategySelector<T> {
T selectStrategy(String key, Map<String, T> strategies);
}
// 基于配置的策略选择器
public class ConfigBasedStrategySelector<T> implements StrategySelector<T> {
private final String defaultStrategy;
public ConfigBasedStrategySelector(String defaultStrategy) {
this.defaultStrategy = defaultStrategy;
}
@Override
public T selectStrategy(String key, Map<String, T> strategies) {
String strategyKey = getStrategyKeyFromConfig(key);
T strategy = strategies.get(strategyKey);
if (strategy == null) {
strategy = strategies.get(defaultStrategy);
}
return strategy;
}
}
// 基于规则的策略选择器
public class RuleBasedStrategySelector<T> implements StrategySelector<T> {
private final List<StrategyRule<T>> rules;
@Override
public T selectStrategy(String key, Map<String, T> strategies) {
for (StrategyRule<T> rule : rules) {
if (rule.matches(key)) {
return rule.getStrategy(strategies);
}
}
return strategies.values().iterator().next();
}
}
2. 策略生命周期管理
难点
- 策略对象的创建和销毁
- 策略的缓存和复用
- 策略的线程安全性
解决方案
java
// 策略工厂接口
public interface StrategyFactory<T> {
T createStrategy(String strategyType);
void destroyStrategy(T strategy);
}
// 单例策略工厂
public class SingletonStrategyFactory<T> implements StrategyFactory<T> {
private final Map<String, T> strategyCache = new ConcurrentHashMap<>();
private final Function<String, T> strategyCreator;
public SingletonStrategyFactory(Function<String, T> strategyCreator) {
this.strategyCreator = strategyCreator;
}
@Override
public T createStrategy(String strategyType) {
return strategyCache.computeIfAbsent(strategyType, strategyCreator);
}
@Override
public void destroyStrategy(T strategy) {
// 清理资源
strategyCache.values().removeIf(s -> s == strategy);
}
}
3. 策略参数传递
难点
- 不同策略可能需要不同的参数
- 参数类型安全
- 参数验证
解决方案
java
// 策略上下文
public class StrategyContext {
private final Map<String, Object> parameters = new HashMap<>();
public <T> T getParameter(String key, Class<T> type) {
Object value = parameters.get(key);
if (value != null && type.isAssignableFrom(value.getClass())) {
return type.cast(value);
}
return null;
}
public void setParameter(String key, Object value) {
parameters.put(key, value);
}
}
// 增强的策略接口
public interface EnhancedStrategy {
void execute(StrategyContext context);
}
4. 策略组合和链式调用
难点
- 多个策略的组合使用
- 策略的执行顺序
- 策略间的数据传递
解决方案
java
// 策略链
public class StrategyChain<T> {
private final List<Strategy<T>> strategies = new ArrayList<>();
public StrategyChain<T> addStrategy(Strategy<T> strategy) {
strategies.add(strategy);
return this;
}
public T execute(T input) {
T result = input;
for (Strategy<T> strategy : strategies) {
result = strategy.execute(result);
}
return result;
}
}
// 组合策略
public class CompositeStrategy<T> implements Strategy<T> {
private final List<Strategy<T>> strategies;
public CompositeStrategy(List<Strategy<T>> strategies) {
this.strategies = strategies;
}
@Override
public T execute(T input) {
T result = input;
for (Strategy<T> strategy : strategies) {
result = strategy.execute(result);
}
return result;
}
}
Spring源码中的策略模式应用
1. ResourceLoader策略模式
Spring使用策略模式来处理不同类型的资源加载:
java
// ResourceLoader接口
public interface ResourceLoader {
Resource getResource(String location);
ClassLoader getClassLoader();
}
// 具体实现类
public class DefaultResourceLoader implements ResourceLoader {
@Override
public Resource getResource(String location) {
if (location.startsWith("/")) {
return getResourceByPath(location);
} else if (location.startsWith(CLASSPATH_URL_PREFIX)) {
return new ClassPathResource(location.substring(CLASSPATH_URL_PREFIX.length()), getClassLoader());
} else if (location.startsWith("file:")) {
return new FileUrlResource(location);
} else if (location.startsWith("http:")) {
return new UrlResource(location);
} else {
return getResourceByPath(location);
}
}
}
2. BeanDefinitionReader策略模式
Spring使用策略模式来支持不同的Bean定义读取方式:
java
// BeanDefinitionReader接口
public interface BeanDefinitionReader {
BeanDefinitionRegistry getRegistry();
ResourceLoader getResourceLoader();
ClassLoader getBeanClassLoader();
BeanNameGenerator getBeanNameGenerator();
int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException;
int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException;
int loadBeanDefinitions(String location) throws BeanDefinitionStoreException;
int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException;
}
// XML Bean定义读取器
public class XmlBeanDefinitionReader implements BeanDefinitionReader {
// XML解析实现
}
// Properties Bean定义读取器
public class PropertiesBeanDefinitionReader implements BeanDefinitionReader {
// Properties解析实现
}
// Groovy Bean定义读取器
public class GroovyBeanDefinitionReader implements BeanDefinitionReader {
// Groovy解析实现
}
3. ViewResolver策略模式
Spring MVC使用策略模式来支持不同的视图解析方式:
java
// ViewResolver接口
public interface ViewResolver {
View resolveViewName(String viewName, Locale locale) throws Exception;
}
// 内部资源视图解析器
public class InternalResourceViewResolver extends UrlBasedViewResolver {
@Override
protected View buildView(String viewName) throws Exception {
InternalResourceView view = (InternalResourceView) super.buildView(viewName);
if (this.alwaysInclude != null) {
view.setAlwaysInclude(this.alwaysInclude);
}
return view;
}
}
// Thymeleaf视图解析器
public class ThymeleafViewResolver extends AbstractCachingViewResolver {
@Override
protected View createView(String viewName, Locale locale) throws Exception {
if (!canHandle(viewName, locale)) {
return null;
}
return super.createView(viewName, locale);
}
}
4. PlatformTransactionManager策略模式
Spring使用策略模式来支持不同的事务管理方式:
java
// 事务管理器接口
public interface PlatformTransactionManager {
TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;
void commit(TransactionStatus status) throws TransactionException;
void rollback(TransactionStatus status) throws TransactionException;
}
// JDBC事务管理器
public class DataSourceTransactionManager extends AbstractPlatformTransactionManager {
@Override
protected Object doGetTransaction() {
DataSourceTransactionObject txObject = new DataSourceTransactionObject();
txObject.setSavepointAllowed(isNestedTransactionAllowed());
ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(obtainDataSource());
txObject.setConnectionHolder(conHolder, false);
return txObject;
}
}
// JTA事务管理器
public class JtaTransactionManager extends AbstractPlatformTransactionManager {
@Override
protected Object doGetTransaction() {
JtaTransactionObject txObject = new JtaTransactionObject();
txObject.setUserTransaction(this.userTransaction);
txObject.setTransactionManager(this.transactionManager);
return txObject;
}
}
5. HandlerMapping策略模式
Spring MVC使用策略模式来支持不同的请求映射方式:
java
// 处理器映射接口
public interface HandlerMapping {
HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
}
// 注解处理器映射
public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMapping {
@Override
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
}
}
// 简单URL处理器映射
public class SimpleUrlHandlerMapping extends AbstractUrlHandlerMapping {
@Override
protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
Object handler = lookupHandler(lookupPath, request);
if (handler == null) {
Object rawHandler = null;
if (lookupPath.equals("/")) {
rawHandler = getRootHandler();
}
if (rawHandler == null) {
rawHandler = getDefaultHandler();
}
if (rawHandler != null) {
handler = (rawHandler instanceof String ?
obtainApplicationContext().getBean((String) rawHandler) : rawHandler);
}
}
return handler;
}
}
6. InstantiationStrategy策略模式
Spring使用策略模式来支持不同的Bean实例化方式:
java
// 实例化策略接口
public interface InstantiationStrategy {
Object instantiate(RootBeanDefinition bd, String beanName, BeanFactory owner) throws BeansException;
Object instantiate(RootBeanDefinition bd, String beanName, BeanFactory owner, Constructor<?> ctor, Object... args) throws BeansException;
Object instantiate(RootBeanDefinition bd, String beanName, BeanFactory owner, Object factoryBean, Method factoryMethod, Object... args) throws BeansException;
}
// 简单实例化策略
public class SimpleInstantiationStrategy implements InstantiationStrategy {
@Override
public Object instantiate(RootBeanDefinition bd, String beanName, BeanFactory owner) {
if (bd.getMethodOverrides().isEmpty()) {
Constructor<?> constructorToUse;
synchronized (bd.constructorArgumentLock) {
constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;
if (constructorToUse == null) {
final Class<?> clazz = bd.getBeanClass();
if (clazz.isInterface()) {
throw new BeanInstantiationException(clazz, "Specified class is an interface");
}
try {
if (System.getSecurityManager() != null) {
constructorToUse = AccessController.doPrivileged((PrivilegedAction<Constructor<?>>) clazz::getDeclaredConstructor);
} else {
constructorToUse = clazz.getDeclaredConstructor();
}
bd.resolvedConstructorOrFactoryMethod = constructorToUse;
} catch (Throwable ex) {
throw new BeanInstantiationException(clazz, "No default constructor found", ex);
}
}
}
return BeanUtils.instantiateClass(constructorToUse);
} else {
return instantiateWithMethodInjection(bd, beanName, owner);
}
}
}
// CGLIB实例化策略
public class CglibSubclassingInstantiationStrategy extends SimpleInstantiationStrategy {
@Override
public Object instantiate(RootBeanDefinition bd, String beanName, BeanFactory owner) {
if (!bd.hasMethodOverrides()) {
Constructor<?> constructorToUse;
synchronized (bd.constructorArgumentLock) {
constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;
if (constructorToUse == null) {
final Class<?> clazz = bd.getBeanClass();
if (clazz.isInterface()) {
throw new BeanInstantiationException(clazz, "Specified class is an interface");
}
try {
if (System.getSecurityManager() != null) {
constructorToUse = AccessController.doPrivileged((PrivilegedAction<Constructor<?>>) clazz::getDeclaredConstructor);
} else {
constructorToUse = clazz.getDeclaredConstructor();
}
bd.resolvedConstructorOrFactoryMethod = constructorToUse;
} catch (Throwable ex) {
throw new BeanInstantiationException(clazz, "No default constructor found", ex);
}
}
}
return BeanUtils.instantiateClass(constructorToUse);
} else {
return instantiateWithMethodInjection(bd, beanName, owner);
}
}
}
最佳实践与设计建议
1. 策略接口设计原则
java
// 好的策略接口设计
public interface PaymentStrategy {
// 单一职责:只负责支付
PaymentResult pay(PaymentRequest request);
// 支持策略标识
String getStrategyName();
// 支持策略验证
boolean supports(PaymentRequest request);
}
// 避免的设计
public interface BadPaymentStrategy {
// 职责过多:支付、验证、通知等
PaymentResult pay(PaymentRequest request);
boolean validate(PaymentRequest request);
void sendNotification(PaymentResult result);
void logPayment(PaymentResult result);
}
2. 策略选择机制
java
// 基于注解的策略选择
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface StrategyType {
String value();
}
@StrategyType("alipay")
public class AlipayStrategy implements PaymentStrategy {
// 实现
}
// 策略注册器
@Component
public class StrategyRegistry {
private final Map<String, PaymentStrategy> strategies = new HashMap<>();
@PostConstruct
public void initStrategies() {
// 扫描并注册所有策略
ApplicationContext context = getApplicationContext();
Map<String, PaymentStrategy> strategyBeans = context.getBeansOfType(PaymentStrategy.class);
for (PaymentStrategy strategy : strategyBeans.values()) {
StrategyType annotation = strategy.getClass().getAnnotation(StrategyType.class);
if (annotation != null) {
strategies.put(annotation.value(), strategy);
}
}
}
public PaymentStrategy getStrategy(String type) {
return strategies.get(type);
}
}
3. 策略配置管理
java
// 策略配置
@Configuration
public class StrategyConfiguration {
@Bean
@ConditionalOnProperty(name = "payment.alipay.enabled", havingValue = "true")
public PaymentStrategy alipayStrategy() {
return new AlipayStrategy();
}
@Bean
@ConditionalOnProperty(name = "payment.wechat.enabled", havingValue = "true")
public PaymentStrategy wechatPayStrategy() {
return new WechatPayStrategy();
}
@Bean
public StrategySelector<PaymentStrategy> paymentStrategySelector() {
return new ConfigBasedStrategySelector<>("alipay");
}
}
4. 策略性能优化
java
// 策略缓存
@Component
public class CachedStrategyRegistry {
private final Map<String, PaymentStrategy> strategyCache = new ConcurrentHashMap<>();
private final StrategyFactory<PaymentStrategy> strategyFactory;
public PaymentStrategy getStrategy(String type) {
return strategyCache.computeIfAbsent(type, strategyFactory::createStrategy);
}
@PreDestroy
public void clearCache() {
strategyCache.clear();
}
}
// 策略预热
@Component
public class StrategyWarmupService {
@EventListener
public void onApplicationReady(ApplicationReadyEvent event) {
// 预热常用策略
List<String> commonStrategies = Arrays.asList("alipay", "wechat");
for (String strategyType : commonStrategies) {
strategyRegistry.getStrategy(strategyType);
}
}
}
5. 策略监控和日志
java
// 策略执行监控
@Component
public class StrategyExecutionMonitor {
private final MeterRegistry meterRegistry;
public <T> T executeWithMonitoring(String strategyName, Supplier<T> strategyExecution) {
Timer.Sample sample = Timer.start(meterRegistry);
try {
T result = strategyExecution.get();
sample.stop(Timer.builder("strategy.execution.time")
.tag("strategy", strategyName)
.tag("status", "success")
.register(meterRegistry));
return result;
} catch (Exception e) {
sample.stop(Timer.builder("strategy.execution.time")
.tag("strategy", strategyName)
.tag("status", "error")
.register(meterRegistry));
throw e;
}
}
}
// 策略执行日志
@Aspect
@Component
public class StrategyExecutionAspect {
private static final Logger logger = LoggerFactory.getLogger(StrategyExecutionAspect.class);
@Around("execution(* com.example.strategy.*.execute(..))")
public Object logStrategyExecution(ProceedingJoinPoint joinPoint) throws Throwable {
String strategyName = joinPoint.getTarget().getClass().getSimpleName();
Object[] args = joinPoint.getArgs();
logger.info("Executing strategy: {} with args: {}", strategyName, args);
long startTime = System.currentTimeMillis();
try {
Object result = joinPoint.proceed();
long executionTime = System.currentTimeMillis() - startTime;
logger.info("Strategy {} executed successfully in {}ms", strategyName, executionTime);
return result;
} catch (Exception e) {
long executionTime = System.currentTimeMillis() - startTime;
logger.error("Strategy {} failed after {}ms", strategyName, executionTime, e);
throw e;
}
}
}
总结
策略模式是一种非常实用的设计模式,在Spring框架中得到了广泛应用。通过合理使用策略模式,可以:
- 提高代码的可维护性:将算法封装在独立的类中,便于修改和扩展
- 增强系统的灵活性:可以在运行时动态选择算法
- 降低代码的耦合度:策略与使用策略的客户端解耦
- 支持开闭原则:对扩展开放,对修改关闭
在实际应用中,需要注意策略选择机制的设计、策略的生命周期管理、参数传递等重难点问题。通过结合Spring的依赖注入和配置管理,可以构建出更加灵活和可维护的策略系统。