设计模式-策略模式深度分析

策略模式深度分析

目录

  1. 策略模式概述
  2. 实际应用场景
  3. 重难点分析
  4. Spring源码中的策略模式应用
  5. 最佳实践与设计建议
  6. 总结

策略模式概述

策略模式(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框架中得到了广泛应用。通过合理使用策略模式,可以:

  1. 提高代码的可维护性:将算法封装在独立的类中,便于修改和扩展
  2. 增强系统的灵活性:可以在运行时动态选择算法
  3. 降低代码的耦合度:策略与使用策略的客户端解耦
  4. 支持开闭原则:对扩展开放,对修改关闭

在实际应用中,需要注意策略选择机制的设计、策略的生命周期管理、参数传递等重难点问题。通过结合Spring的依赖注入和配置管理,可以构建出更加灵活和可维护的策略系统。

相关推荐
辞去归来兮4 小时前
观察者模式 VS. 发布-订阅者模式
设计模式
织_网5 小时前
Electron 核心模块速查表
javascript·electron·策略模式
一叶难遮天7 小时前
Android面试指南(八)
java·设计模式·数组·hashmap·string·android面试·匿名内部类
星空寻流年16 小时前
设计模式第一章(建造者模式)
java·设计模式·建造者模式
蒋星熠17 小时前
Flutter跨平台工程实践与原理透视:从渲染引擎到高质产物
开发语言·python·算法·flutter·设计模式·性能优化·硬件工程
至此流年莫相忘20 小时前
设计模式:策略模式
设计模式·策略模式
ytadpole21 小时前
揭秘设计模式:命令模式-告别混乱,打造优雅可扩展的代码
java·设计模式
努力也学不会java1 天前
【设计模式】 外观模式
设计模式·外观模式
deepwater_zone1 天前
设计模式(策略,观察者,单例,工厂方法)
设计模式