Skip to content

策略模式是什么

策略模式概述

  • 定义
  • 策略模式是一种 行为型设计模式,定义一系列算法(策略),将每个算法封装为独立类,使它们可互换,客户端可动态选择不同策略执行任务。
  • 核心思想
  • 将变化的算法与使用场景分离,降低耦合,支持运行时切换。
  • 组成
  • 策略接口:定义算法规范。
  • 具体策略:实现不同算法。
  • 上下文:持有策略引用,执行算法。

核心点

  • 策略模式通过封装算法提升灵活性,Spring 中广泛用于动态行为选择。

1. 策略模式核心概念

(1) 角色

  • 策略接口(Strategy)
  • 定义算法的抽象方法。
  • 例:interface Strategy
  • 具体策略(Concrete Strategy)
  • 实现策略接口,提供具体算法。
  • 例:ConcreteStrategyA
  • 上下文(Context)
  • 持有策略引用,调用算法。
  • 例:Context
  • 客户端(Client)
  • 配置上下文,选择策略。

(2) 优势

  • 开闭原则
  • 新增策略无需改上下文。
  • 解耦
  • 算法与调用分离。
  • 灵活性
  • 运行时动态切换。

(3) 图示

[Client] --> [Context] --> [Strategy]
                           --> [ConcreteStrategyA]
                           --> [ConcreteStrategyB]

2. 策略模式实现

(1) 代码示例

  • 场景
  • 支付系统支持多种支付方式(支付宝、微信)。
  • 代码
// 策略接口
public interface PaymentStrategy {
    void pay(double amount);
}

// 具体策略
public class AlipayStrategy implements PaymentStrategy {
    @Override
    public void pay(double amount) {
        System.out.println("Paying " + amount + " via Alipay");
    }
}

public class WechatPayStrategy implements PaymentStrategy {
    @Override
    public void pay(double amount) {
        System.out.println("Paying " + amount + " via Wechat");
    }
}

// 上下文
public class PaymentContext {
    private PaymentStrategy strategy;

    public void setStrategy(PaymentStrategy strategy) {
        this.strategy = strategy;
    }

    public void pay(double amount) {
        if (strategy == null) {
            throw new IllegalStateException("Strategy not set");
        }
        strategy.pay(amount);
    }
}

// 客户端
public class Client {
    public static void main(String[] args) {
        PaymentContext context = new PaymentContext();

        // 使用支付宝
        context.setStrategy(new AlipayStrategy());
        context.pay(100.0); // 输出: Paying 100.0 via Alipay

        // 切换微信
        context.setStrategy(new WechatPayStrategy());
        context.pay(200.0); // 输出: Paying 200.0 via Wechat
    }
}

(2) 关键点

  • 动态切换
  • setStrategy 运行时选择算法。
  • 扩展性
  • 新增支付方式(如银联)只需加 UnionPayStrategy
  • 封装
  • 每种支付逻辑独立。

3. 策略模式在 Spring 中的应用

  • 结合您的问题(Spring AOP、工厂模式):
  • Spring 认证
    • AuthenticationProvider 使用策略模式。
    • 例:支持用户名密码、JWT(您提问的单点登录)、OAuth。
public interface AuthenticationProvider {
    Authentication authenticate(Authentication authentication);
}

@Component
public class UsernamePasswordProvider implements AuthenticationProvider {
    @Override
    public Authentication authenticate(Authentication authentication) {
        // 用户名密码验证
        return new UsernamePasswordAuthenticationToken(principal, credentials);
    }
}

@Component
public class JwtProvider implements AuthenticationProvider {
    @Override
    public Authentication authenticate(Authentication authentication) {
        // JWT 验证
        return new JwtAuthenticationToken(token);
    }
}
  • Spring Security 动态选择 AuthenticationProvider
  • Spring 资源加载
  • ResourceLoader 支持不同协议(file:http:)。
  • AOP 切面选择
  • 动态选择切面逻辑(如日志、事务)。
  • 与工厂模式
  • 策略常与工厂结合,工厂创建策略实例:
@Component
public class PaymentStrategyFactory {
    private Map<String, PaymentStrategy> strategies;

    @Autowired
    public PaymentStrategyFactory(List<PaymentStrategy> strategyList) {
        strategies = strategyList.stream()
            .collect(Collectors.toMap(s -> s.getClass().getSimpleName(), s -> s));
    }

    public PaymentStrategy getStrategy(String type) {
        return strategies.get(type);
    }
}

(4) RESTful API 集成

  • 场景
  • API 支持多种序列化格式(JSON、XML)。
  • 示例
public interface Serializer {
    String serialize(Object obj);
}

@Component
public class JsonSerializer implements Serializer {
    @Override
    public String serialize(Object obj) {
        return new ObjectMapper().writeValueAsString(obj);
    }
}

@RestController
public class UserController {
    private Serializer serializer;

    @Autowired
    public void setSerializer(Serializer serializer) {
        this.serializer = serializer;
    }

    @GetMapping("/users")
    public String getUsers() {
        User user = new User(1, "Alice");
        return serializer.serialize(user);
    }
}

4. 使用场景

  • 多算法选择
  • 支付方式、排序算法。
  • 动态行为
  • 认证方式(JWT、OAuth)。
  • 规则引擎
  • 促销规则(满减、折扣)。
  • 格式转换
  • 数据序列化(JSON、XML)。
  • 事件处理
  • 不同事件触发不同逻辑。

与您的问题

  • 单点登录
  • 策略模式实现认证切换(JWT、SAML)。
  • Spring AOP
  • 动态选择切面逻辑(如日志策略)。
  • RESTful API
  • 序列化或响应处理策略。
  • 事务传播
  • 事务管理器选择不同传播行为。

5. 优缺点

优点

  • 开闭原则
  • 新增策略无需改上下文。
  • 解耦
  • 算法独立,易维护。
  • 灵活性
  • 运行时切换策略。

缺点

  • 类膨胀
  • 策略多时类数量增加。
  • 客户端复杂性
  • 需知道所有策略。
  • 初始化开销
  • 动态加载策略需额外逻辑。

6. 策略模式 vs 其他模式

策略 vs 工厂

特性 策略模式 工厂模式
目的 动态选择算法 封装对象创建
关注 行为(算法) 对象实例
结合 工厂可创建策略 策略不涉及创建

策略 vs 状态

  • 策略
  • 选择不同算法,外部控制。
  • 状态
  • 随状态变化行为,内部切换。

策略 vs 模板方法

  • 策略
  • 算法整体替换。
  • 模板方法
  • 固定骨架,子类实现步骤。

7. 最佳实践

  • 接口清晰
  • 策略接口方法单一职责。
  • 结合工厂
  • 用工厂管理策略:
strategy = factory.getStrategy("alipay");
  • Spring 注入
  • @Autowired List<Strategy> 自动收集。
  • 命名规范
  • JsonSerializerAlipayStrategy

8. 延伸与面试角度

  • 与 Spring
  • AuthenticationProviderResourceLoader 是策略模式。
  • 与工厂
  • 工厂创建策略实例。
  • 与 AOP
  • 策略定义切面行为。
  • 实际应用
  • 电商:支付、促销策略。
  • 微服务:认证、序列化。
  • 面试点
  • 问“定义”时,提角色和开闭原则。
  • 问“场景”时,提 Spring 和支付示例。

9. 总结

策略模式通过接口封装算法,支持动态切换,适用于支付、认证等场景。Spring 的认证和资源加载广泛使用策略模式。结合您的问题,策略可实现 SSO 认证切换或 API 序列化。面试时,可提代码、Spring 案例或与工厂模式的结合,展示理解深度。


如果您想深入某场景(如 Spring Security 的策略实现)或有具体问题,请告诉我,我可以进一步优化!