设计模式-策略模式深度分析
策略模式深度分析
目录
- 策略模式概述
- 实际应用场景
- 重难点分析
- Spring源码中的策略模式应用
- 最佳实践与设计建议
- 总结
策略模式概述
策略模式(Strategy Pattern)是一种行为型设计模式,属于GoF 23种设计模式之一。它定义了一系列算法,将每个算法封装起来,并使它们可以相互替换。策略模式让算法的变化独立于使用算法的客户端。
核心组件
- Strategy(策略接口):定义所有具体策略的公共接口
- ConcreteStrategy(具体策略):实现策略接口的具体算法
- Context(上下文):持有一个策略对象的引用,并调用策略对象的方法
设计原则
- 开闭原则:对扩展开放,对修改关闭
- 单一职责原则:每个策略类只负责一种算法
- 依赖倒置原则:依赖抽象而不是具体实现
实际应用场景
1. 支付系统
// 支付策略接口
public interface PaymentStrategy {void pay(BigDecimal amount);
}// 支付宝支付策略
public class AlipayStrategy implements PaymentStrategy {@Overridepublic void pay(BigDecimal amount) {System.out.println("使用支付宝支付:" + amount);}
}// 微信支付策略
public class WechatPayStrategy implements PaymentStrategy {@Overridepublic 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. 数据压缩系统
// 压缩策略接口
public interface CompressionStrategy {byte[] compress(byte[] data);byte[] decompress(byte[] compressedData);
}// ZIP压缩策略
public class ZipCompressionStrategy implements CompressionStrategy {@Overridepublic byte[] compress(byte[] data) {// ZIP压缩实现return zipCompress(data);}@Overridepublic byte[] decompress(byte[] compressedData) {// ZIP解压实现return zipDecompress(compressedData);}
}// GZIP压缩策略
public class GzipCompressionStrategy implements CompressionStrategy {@Overridepublic byte[] compress(byte[] data) {// GZIP压缩实现return gzipCompress(data);}@Overridepublic byte[] decompress(byte[] compressedData) {// GZIP解压实现return gzipDecompress(compressedData);}
}
3. 日志记录系统
// 日志策略接口
public interface LoggingStrategy {void log(String message, LogLevel level);
}// 文件日志策略
public class FileLoggingStrategy implements LoggingStrategy {@Overridepublic void log(String message, LogLevel level) {// 写入文件writeToFile(message, level);}
}// 数据库日志策略
public class DatabaseLoggingStrategy implements LoggingStrategy {@Overridepublic void log(String message, LogLevel level) {// 写入数据库writeToDatabase(message, level);}
}// 控制台日志策略
public class ConsoleLoggingStrategy implements LoggingStrategy {@Overridepublic void log(String message, LogLevel level) {// 输出到控制台System.out.println(level + ": " + message);}
}
4. 排序算法选择
// 排序策略接口
public interface SortStrategy {void sort(int[] array);
}// 快速排序策略
public class QuickSortStrategy implements SortStrategy {@Overridepublic void sort(int[] array) {// 快速排序实现quickSort(array, 0, array.length - 1);}
}// 归并排序策略
public class MergeSortStrategy implements SortStrategy {@Overridepublic void sort(int[] array) {// 归并排序实现mergeSort(array, 0, array.length - 1);}
}// 堆排序策略
public class HeapSortStrategy implements SortStrategy {@Overridepublic void sort(int[] array) {// 堆排序实现heapSort(array);}
}
5. 数据验证系统
// 验证策略接口
public interface ValidationStrategy {boolean validate(String data);
}// 邮箱验证策略
public class EmailValidationStrategy implements ValidationStrategy {@Overridepublic boolean validate(String data) {return data.matches("^[A-Za-z0-9+_.-]+@(.+)$");}
}// 手机号验证策略
public class PhoneValidationStrategy implements ValidationStrategy {@Overridepublic boolean validate(String data) {return data.matches("^1[3-9]\\d{9}$");}
}// 身份证验证策略
public class IdCardValidationStrategy implements ValidationStrategy {@Overridepublic boolean validate(String data) {return data.matches("^\\d{17}[\\dXx]$");}
}
重难点分析
1. 策略选择机制设计
难点
- 如何根据运行时条件动态选择合适的策略
- 避免硬编码策略选择逻辑
- 支持策略的优先级和回退机制
解决方案
// 策略选择器接口
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;}@Overridepublic 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;@Overridepublic 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. 策略生命周期管理
难点
- 策略对象的创建和销毁
- 策略的缓存和复用
- 策略的线程安全性
解决方案
// 策略工厂接口
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;}@Overridepublic T createStrategy(String strategyType) {return strategyCache.computeIfAbsent(strategyType, strategyCreator);}@Overridepublic void destroyStrategy(T strategy) {// 清理资源strategyCache.values().removeIf(s -> s == strategy);}
}
3. 策略参数传递
难点
- 不同策略可能需要不同的参数
- 参数类型安全
- 参数验证
解决方案
// 策略上下文
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. 策略组合和链式调用
难点
- 多个策略的组合使用
- 策略的执行顺序
- 策略间的数据传递
解决方案
// 策略链
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;}@Overridepublic T execute(T input) {T result = input;for (Strategy<T> strategy : strategies) {result = strategy.execute(result);}return result;}
}
Spring源码中的策略模式应用
1. ResourceLoader策略模式
Spring使用策略模式来处理不同类型的资源加载:
// ResourceLoader接口
public interface ResourceLoader {Resource getResource(String location);ClassLoader getClassLoader();
}// 具体实现类
public class DefaultResourceLoader implements ResourceLoader {@Overridepublic 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定义读取方式:
// 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使用策略模式来支持不同的视图解析方式:
// ViewResolver接口
public interface ViewResolver {View resolveViewName(String viewName, Locale locale) throws Exception;
}// 内部资源视图解析器
public class InternalResourceViewResolver extends UrlBasedViewResolver {@Overrideprotected 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 {@Overrideprotected View createView(String viewName, Locale locale) throws Exception {if (!canHandle(viewName, locale)) {return null;}return super.createView(viewName, locale);}
}
4. PlatformTransactionManager策略模式
Spring使用策略模式来支持不同的事务管理方式:
// 事务管理器接口
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 {@Overrideprotected 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 {@Overrideprotected Object doGetTransaction() {JtaTransactionObject txObject = new JtaTransactionObject();txObject.setUserTransaction(this.userTransaction);txObject.setTransactionManager(this.transactionManager);return txObject;}
}
5. HandlerMapping策略模式
Spring MVC使用策略模式来支持不同的请求映射方式:
// 处理器映射接口
public interface HandlerMapping {HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
}// 注解处理器映射
public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMapping {@Overrideprotected 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 {@Overrideprotected 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实例化方式:
// 实例化策略接口
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 {@Overridepublic 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 {@Overridepublic 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. 策略接口设计原则
// 好的策略接口设计
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. 策略选择机制
// 基于注解的策略选择
@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<>();@PostConstructpublic 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. 策略配置管理
// 策略配置
@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();}@Beanpublic StrategySelector<PaymentStrategy> paymentStrategySelector() {return new ConfigBasedStrategySelector<>("alipay");}
}
4. 策略性能优化
// 策略缓存
@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);}@PreDestroypublic void clearCache() {strategyCache.clear();}
}// 策略预热
@Component
public class StrategyWarmupService {@EventListenerpublic void onApplicationReady(ApplicationReadyEvent event) {// 预热常用策略List<String> commonStrategies = Arrays.asList("alipay", "wechat");for (String strategyType : commonStrategies) {strategyRegistry.getStrategy(strategyType);}}
}
5. 策略监控和日志
// 策略执行监控
@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的依赖注入和配置管理,可以构建出更加灵活和可维护的策略系统。