设计模式——策略设计模式(行为型)
摘要
策略设计模式是一种行为型设计模式,它定义了一系列算法并将每个算法封装起来,使它们可以相互替换。该模式让算法的变化独立于使用算法的客户,从而使得算法可以灵活地切换和扩展。其主要角色包括策略接口、具体策略类和环境类。策略模式的结构通过类图和时序图进行展示,实现方式涵盖定义策略接口、实现具体策略类、定义环境类等步骤。它适用于多种场景,如在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 {@Overridepublic void execute() {System.out.println("执行策略 A");}
}@Component("strategyB")
public class ConcreteStrategyB implements Strategy {@Overridepublic 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;@Autowiredpublic 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"); // 执行策略AstrategyService.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 {@Overridepublic boolean checkRisk(String userId) {System.out.println("执行信用评分风控,用户:" + userId);// 伪代码:查询用户信用分,判断是否高风险return true; // 通过}
}@Component("blacklistStrategy")
public class BlacklistStrategy implements RiskControlStrategy {@Overridepublic boolean checkRisk(String userId) {System.out.println("执行黑名单风控,用户:" + userId);// 伪代码:判断用户是否在黑名单中return false; // 拦截}
}@Component("behaviorStrategy")
public class BehaviorStrategy implements RiskControlStrategy {@Overridepublic 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 {@Autowiredprivate 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 {@Autowiredprivate 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) | 工厂模式负责策略对象的创建,结合策略模式实现动态策略实例化,避免客户端直接依赖具体策略类。 |
策略+工厂 | 通过工厂动态创建或获取策略实例,简化策略管理,便于新增策略。 |
策略+责任链模式 | 多个策略按责任链顺序依次执行,适合风控流程中多步校验和规则链式处理。 |
策略+装饰器模式 | 在策略的基础上动态添加额外行为(如日志、缓存、权限控制),增强策略功能。 |
策略+模板方法模式 | 模板方法定义固定流程,策略负责具体步骤的算法实现,二者分工清晰,灵活替换。 |
策略+桥接模式 | 桥接模式分离策略接口与实现,策略作为抽象层一部分,便于独立扩展和变化。 |
策略+命令模式 | 命令模式封装请求,策略定义请求的处理算法,便于请求调用与执行分离。 |
策略+观察者模式 | 观察者模式监听策略执行结果,实现事件驱动的策略调整和联动处理。 |
策略+代理模式 | 代理在调用策略前后添加横切逻辑,如权限检查、性能统计。 |
策略+状态模式 | 状态模式控制状态切换,策略定义每状态下的具体行为。 |
简单示例说明
- 策略 + 工厂:风控策略的工厂负责创建或注入具体策略,客户端通过工厂获取策略实例。
- 策略 + 责任链:风控中,多个风控策略组成责任链,一个接一个执行直到拦截或全部通过。
- 策略 + 装饰器:对某个策略加日志功能或缓存功能,用装饰器包装策略实例。
博文参考
- 5. 策略模式 — Graphic Design Patterns
- 策略设计模式