设计模式——策略设计模式(行为型)

0 阅读7分钟

摘要

策略设计模式是一种行为型设计模式,它定义了一系列算法并将每个算法封装起来,使它们可以相互替换。该模式让算法的变化独立于使用算法的客户,从而使得算法可以灵活地切换和扩展。其主要角色包括策略接口、具体策略类和环境类。策略模式的结构通过类图和时序图进行展示,实现方式涵盖定义策略接口、实现具体策略类、定义环境类等步骤。它适用于多种场景,如在Spring中动态选择策略等,同时也有其不适用的场景。实战示例包括需求背景、策略接口及实现类、策略上下文类等,有助于理解策略模式的实际应用。

1. 策略设计模式定义

策略设计模式(Strategy Pattern)是一种行为型设计模式,它定义了一系列算法(策略),并将每个算法封装起来,使它们可以相互替换。策略模式让算法的变化独立于使用算法的客户,从而使得算法可以灵活地切换和扩展。

核心思想: 将不同的算法封装成独立的策略类,客户端通过调用统一的接口来选择和执行具体的策略,而不用关心具体的实现细节。

1.1.1. 策略设计模式的主要角色:

  • 策略接口(Strategy) :定义一系列算法的公共接口。
  • 具体策略类(ConcreteStrategy) :实现策略接口的具体算法。
  • 环境类(Context) :持有一个策略对象的引用,负责调用具体策略的方法。

2. 策略设计模式结构

策略模式包含如下角色:

  • Context: 环境类
  • Strategy: 抽象策略类
  • ConcreteStrategy: 具体策略类

2.1. 策略设计模式类图

2.2. 策略设计模式时序图

3. 策略设计模式实现方式

3.1. 定义策略接口(Strategy)

定义一个公共接口,声明所有具体策略类需要实现的方法。

public interface Strategy {
    void execute();
}

3.2. 实现具体策略类(ConcreteStrategy)

实现策略接口的多个具体类,分别封装不同的算法或行为。

@Component("strategyA")
public class ConcreteStrategyA implements Strategy {
    @Override
    public void execute() {
        System.out.println("执行策略 A");
    }
}

@Component("strategyB")
public class ConcreteStrategyB implements Strategy {
    @Override
    public void execute() {
        System.out.println("执行策略 B");
    }
}

3.3. 定义环境类(Context)

环境类持有策略接口引用,通过调用接口的方法来执行具体策略。

@Component
public class StrategyContext {

    private Strategy strategy;

    // 通过setter注入当前使用的策略
    public void setStrategy(Strategy strategy) {
        this.strategy = strategy;
    }

    public void executeStrategy() {
        strategy.execute();
    }
}

3.4. 在Spring中动态选择策略

通过Spring容器自动注入所有策略类,利用策略名称或者业务标识动态选择执行的策略。

@Component
public class StrategyService {

    private final Map<String, Strategy> strategyMap;

    @Autowired
    public StrategyService(Map<String, Strategy> strategyMap) {
        this.strategyMap = strategyMap;
    }

    public void execute(String strategyName) {
        Strategy strategy = strategyMap.get(strategyName);
        if (strategy == null) {
            throw new IllegalArgumentException("无效的策略名称:" + strategyName);
        }
        strategy.execute();
    }
}

3.5. 使用示例(调用)


@Autowired
private StrategyService strategyService;

public void test() {
    strategyService.execute("strategyA");  // 执行策略A
    strategyService.execute("strategyB");  // 执行策略B
}

3.6. 策略模式总结

  • 策略接口定义公共方法;
  • 具体策略类实现不同算法;
  • 环境类调用策略接口;
  • Spring容器管理策略类,通过注解和自动注入动态选择策略。

4. 策略设计模式适合场景

4.1. ✅ 适合使用策略设计模式的场景

场景说明
多算法动态切换系统中存在多种算法或行为,需要根据业务动态选择。
避免复杂条件判断需要减少大量 if-else 或 switch-case 的代码。
算法封装与扩展不同算法实现统一接口,方便互换和新增策略。
遵循单一职责原则将变化的算法封装,保持代码清晰易维护。
支持新增策略不影响客户端新策略可增加而无需修改客户端代码,符合开闭原则。
业务规则频繁变动算法或业务规则经常调整,需灵活切换实现。

4.2. ❌ 不适合使用策略设计模式的场景

场景原因
单一算法场景只有一种算法,没有多策略选择,策略模式无意义。
算法简单且稳定算法逻辑简单且变化不大,策略模式增加复杂度。
策略间依赖强策略之间耦合较紧,无法独立替换。
频繁变更策略映射频繁修改策略注册或映射,维护成本较高。
系统规模较小设计复杂度不必要增加,适合直接调用简单实现。

5. 策略设计模式实战示例

5.1. 需求背景

假设风控系统中,有不同的风控策略(如:信用评分风控、黑名单风控、行为风控),业务根据不同场景动态选择策略执行风控校验。

5.2. 策略接口

public interface RiskControlStrategy {
    boolean checkRisk(String userId);
}

5.3. 具体策略实现类

import org.springframework.stereotype.Component;

@Component("creditScoreStrategy")
public class CreditScoreStrategy implements RiskControlStrategy {
    @Override
    public boolean checkRisk(String userId) {
        System.out.println("执行信用评分风控,用户:" + userId);
        // 伪代码:查询用户信用分,判断是否高风险
        return true;  // 通过
    }
}

@Component("blacklistStrategy")
public class BlacklistStrategy implements RiskControlStrategy {
    @Override
    public boolean checkRisk(String userId) {
        System.out.println("执行黑名单风控,用户:" + userId);
        // 伪代码:判断用户是否在黑名单中
        return false; // 拦截
    }
}

@Component("behaviorStrategy")
public class BehaviorStrategy implements RiskControlStrategy {
    @Override
    public boolean checkRisk(String userId) {
        System.out.println("执行行为风控,用户:" + userId);
        // 伪代码:分析用户行为风险
        return true;
    }
}

5.4. 策略上下文类(策略注册表)

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Map;

@Component
public class RiskControlStrategyContext {

    @Autowired
    private Map<String, RiskControlStrategy> strategyMap;

    public RiskControlStrategy getStrategy(String strategyType) {
        return strategyMap.getOrDefault(strategyType, strategyMap.get("creditScoreStrategy"));
    }
}

5.5. 业务调用示例(例如 Controller 或 Service)

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class RiskControlService {

    @Autowired
    private RiskControlStrategyContext strategyContext;

    public boolean executeRiskCheck(String userId, String strategyType) {
        RiskControlStrategy strategy = strategyContext.getStrategy(strategyType);
        return strategy.checkRisk(userId);
    }
}

5.6. 策略模式使用示例

// 比如Controller层调用
@Autowired
private RiskControlService riskControlService;

public void handleRequest(String userId, String riskType) {
    boolean passed = riskControlService.executeRiskCheck(userId, riskType);
    if (passed) {
        System.out.println("风控通过");
    } else {
        System.out.println("风控拦截");
    }
}

5.7. 总结

  • 各策略实现了统一接口,方便动态切换。
  • Spring容器自动扫描并注入所有策略,实现“策略注册表”。
  • 业务只需调用策略上下文类,无需关心具体策略实现。
  • 支持轻松扩展,新增策略只需新增实现并标注组件注解即可。

6. 策略设计模式思考

6.1. 哪些设计模式与策略模式常用与实战开发中?

策略设计模式常常和其他设计模式组合使用,以实现更加灵活、解耦且可扩展的系统设计。下面列出几个策略模式常见的组合模式及其实战意义

组合模式作用和实战意义
工厂模式(Factory)工厂模式负责策略对象的创建,结合策略模式实现动态策略实例化,避免客户端直接依赖具体策略类。
策略+工厂通过工厂动态创建或获取策略实例,简化策略管理,便于新增策略。
策略+责任链模式多个策略按责任链顺序依次执行,适合风控流程中多步校验和规则链式处理。
策略+装饰器模式在策略的基础上动态添加额外行为(如日志、缓存、权限控制),增强策略功能。
策略+模板方法模式模板方法定义固定流程,策略负责具体步骤的算法实现,二者分工清晰,灵活替换。
策略+桥接模式桥接模式分离策略接口与实现,策略作为抽象层一部分,便于独立扩展和变化。
策略+命令模式命令模式封装请求,策略定义请求的处理算法,便于请求调用与执行分离。
策略+观察者模式观察者模式监听策略执行结果,实现事件驱动的策略调整和联动处理。
策略+代理模式代理在调用策略前后添加横切逻辑,如权限检查、性能统计。
策略+状态模式状态模式控制状态切换,策略定义每状态下的具体行为。

简单示例说明

  • 策略 + 工厂:风控策略的工厂负责创建或注入具体策略,客户端通过工厂获取策略实例。
  • 策略 + 责任链:风控中,多个风控策略组成责任链,一个接一个执行直到拦截或全部通过。
  • 策略 + 装饰器:对某个策略加日志功能或缓存功能,用装饰器包装策略实例。

博文参考