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

策略模式深度分析

目录

  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的依赖注入和配置管理,可以构建出更加灵活和可维护的策略系统。

相关推荐
触底反弹12 分钟前
🤯 面试被问 AI Workflow 和 Agent 有啥区别?3 张图 + 2 段代码讲清楚!
人工智能·设计模式·面试
张小姐的猫18 小时前
【Linux】网络编程 —— HTTP协议(上)
linux·运维·服务器·网络·http·单例模式·策略模式
杨充21 小时前
10.可测试性实战设计
设计模式·开源·代码规范
杨充21 小时前
9.重构十二式的实战
设计模式·开源·代码规范
杨充21 小时前
6.设计原则的全景图
设计模式·开源·全栈
杨充21 小时前
2.面向对象的特性
设计模式
杨充21 小时前
7.SOLID原则案例汇
设计模式·开源·全栈
杨充21 小时前
8.反模式与坏味道
设计模式·开源·代码规范
杨充21 小时前
3.接口vs抽象类比较
设计模式