设计模式之策略模式
策略模式(Strategy Pattern)全解析:Java 架构师从理论到企业级实战
在 Java 企业级开发、微服务架构、分布式系统、电商金融等核心领域,代码的可扩展性、可维护性、解耦性是架构设计的核心指标。设计模式作为软件工程的最佳实践,是解决这些问题的核心工具;而策略模式作为行为型设计模式的经典代表,是消除代码中臃肿的if-else/switch分支、实现算法灵活切换、完美契合设计模式七大原则的最优解。
作为 Java 架构师,本文将从设计模式七大原则为基石,深度拆解策略模式的核心思想、结构、分层代码实现,结合SpringBoot 企业级实战、真实业务场景、主流框架源码应用,全面剖析策略模式的落地价值与核心优势,全文内容深度覆盖架构设计、编码实践、业务落地全维度,助力你彻底掌握策略模式的精髓。
前言:为什么我们需要策略模式?
在实际项目开发中,我们经常遇到同一行为存在多种实现算法的场景:
- 电商结算:无优惠、满减、折扣、优惠券、秒杀等多种优惠算法;
- 支付系统:微信支付、支付宝、银联、云闪付等多种支付渠道;
- 文件处理:Excel、CSV、PDF、Word 等多种文件解析 / 导出算法;
- 登录认证:密码、短信、OAuth2.0、人脸等多种登录验证算法。
传统开发中,我们通常用大量的条件判断语句实现这些逻辑,导致代码臃肿、耦合度高、难以扩展、难以测试。而策略模式的核心价值,就是将算法的定义与算法的使用彻底分离,让算法独立变化、灵活替换,最终让系统架构更优雅、更健壮。
第一部分:设计模式七大核心原则(策略模式的基石)
策略模式之所以成为经典设计模式,核心原因是它完美契合设计模式七大原则。在深入策略模式前,我们必须先吃透这七大原则,这是架构设计的底层逻辑。
| 原则名称 | 英文缩写 | 核心定义 | 设计核心 |
|---|---|---|---|
| 单一职责原则 | SRP | 一个类只负责一项职责,只有一个引起变化的原因 | 高内聚 |
| 开闭原则 | OCP | 软件实体对扩展开放,对修改关闭 | 可扩展 |
| 里氏替换原则 | LSP | 父类引用可无缝替换子类对象,子类不破坏父类契约 | 继承规范 |
| 依赖倒置原则 | DIP | 面向抽象编程,高层依赖抽象,细节依赖抽象 | 解耦 |
| 接口隔离原则 | ISP | 客户端不依赖不需要的接口,接口精简单一 | 接口精简 |
| 迪米特法则 | LOD | 一个对象只与直接朋友通信,最少知道原则 | 低耦合 |
| 合成复用原则 | CRP | 优先使用对象组合 / 聚合,而非继承实现复用 | 弱耦合 |
1. 单一职责原则(SRP)
一个类如果承担多个职责,任意一个职责的变更都会影响其他功能,导致代码难以维护。最优实践:一个类只做一件事。
反例:一个类同时处理支付、退款、提现;
正例:拆分支付策略、退款策略、提现策略,各司其职。
2. 开闭原则(OCP)
软件设计的终极原则:新增功能时,通过扩展代码实现,绝不修改原有核心业务代码,避免修改引发的线上 bug。
反例:新增支付方式时,直接修改原有if-else支付逻辑;
正例:新增支付策略实现类,不改动任何原有代码。
3. 里氏替换原则(LSP)
继承 / 实现必须遵循契约:所有使用父类 / 接口的地方,都可以无缝替换子类 / 实现类对象,子类不能重写父类核心业务方法。
反例:支付实现类随意修改接口契约,导致调用异常;
正例:所有支付策略严格实现支付接口,接口引用可替换任意实现。
4. 依赖倒置原则(DIP)
架构设计的核心解耦原则:高层模块不依赖低层模块,二者都依赖抽象;抽象不依赖细节,细节依赖抽象。
反例:业务 Service 直接依赖AlipayServiceImpl具体实现类;
正例:业务 Service 依赖PayStrategy抽象接口,面向接口编程。
5. 接口隔离原则(ISP)
避免臃肿接口,将大接口拆分为多个小接口,客户端只依赖自己需要的接口。
反例:一个支付接口包含支付、退款、提现、查询所有方法;
正例:拆分PayStrategy、RefundStrategy、WithdrawStrategy独立接口。
6. 迪米特法则(LOD)
最少知道原则:一个对象对其他对象的了解越少越好,只与直接依赖的对象通信。
反例:客户端直接创建所有支付策略对象,耦合所有实现类;
正例:客户端只与上下文类交互,屏蔽具体策略细节。
7. 合成复用原则(CRP)
继承是强耦合,组合是弱耦合:优先使用对象组合 / 聚合实现复用,而非继承。
反例:通过多层继承实现不同优惠逻辑,继承层级混乱;
正例:上下文类通过组合持有策略对象,动态切换算法。
第二部分:策略模式核心基础认知
1. 策略模式官方定义(GoF)
策略模式定义了一系列的算法,将每一个算法封装到独立的类中,并且使它们可以相互替换。策略模式让算法的变化独立于使用算法的客户端。
2. 策略模式核心角色(4 大核心组件)
策略模式是典型的分层设计,将算法定义、算法实现、算法调用、客户端使用彻底分离,四大角色分工明确:
| 角色名称 | 类型 | 核心职责 | 代码表现 |
|---|---|---|---|
| 抽象策略(Strategy) | 接口 / 抽象类 | 定义所有算法的公共契约(方法) | PayStrategy、PromotionStrategy |
| 具体策略(ConcreteStrategy) | 实现类 | 实现抽象策略接口,提供具体算法逻辑 | AlipayStrategy、FullReductionStrategy |
| 上下文(Context) | 业务调度类 | 持有策略对象引用,对外提供统一调用入口,屏蔽客户端直接访问策略 | PayContext、PromotionContext |
| 客户端(Client) | 调用方 | 创建策略对象,传递给上下文,触发算法执行 | Controller/Test 类 |
3. 策略模式 UML 类图(文字描述)
Context类 组合持有Strategy接口对象;Context提供setStrategy()动态切换策略、execute()调用算法;ConcreteStrategyA/B/C实现Strategy接口,重写核心算法方法;- 客户端仅与
Context交互,无需关注具体策略实现。
4. 策略模式核心思想
分离算法定义与算法使用,封装可变算法,开放灵活扩展。
- 可变部分:具体算法实现(封装到策略类);
- 不变部分:算法调用逻辑(封装到上下文);
- 客户端:无感使用算法,无需关心实现细节。
第三部分:反例:传统实现方式的致命痛点
我们以电商商品优惠结算为场景,先看传统if-else实现,直观感受代码的缺陷:
需求
商品原价结算,支持 4 种优惠:无优惠、满 100 减 20、8 折优惠、优惠券减 30。
传统硬编码实现
import java.math.BigDecimal;
/**
* 传统优惠服务:违反所有设计原则
*/
public class TraditionalPromotionService {
/**
* 计算优惠后价格(全是if-else,臃肿到极致)
* @param originalPrice 原价
* @param type 优惠类型:NONE/FULL_REDUCTION/DISCOUNT/COUPON
* @return 优惠后价格
*/
public BigDecimal calculatePrice(BigDecimal originalPrice, String type) {
// 1. 无优惠
if ("NONE".equals(type)) {
return originalPrice;
}
// 2. 满减优惠
else if ("FULL_REDUCTION".equals(type)) {
if (originalPrice.compareTo(new BigDecimal("100")) >= 0) {
return originalPrice.subtract(new BigDecimal("20"));
}
return originalPrice;
}
// 3. 折扣优惠
else if ("DISCOUNT".equals(type)) {
return originalPrice.multiply(new BigDecimal("0.8"));
}
// 4. 优惠券优惠
else if ("COUPON".equals(type)) {
return originalPrice.subtract(new BigDecimal("30"));
}
// 非法类型
else {
throw new IllegalArgumentException("不支持的优惠类型:" + type);
}
}
}
传统写法的致命缺陷(架构师必避坑)
- 违反单一职责:一个类承载所有优惠算法,职责混乱;
- 违反开闭原则:新增秒杀优惠,必须修改
if-else代码,风险极高; - 代码臃肿:分支过多,可读性极差,后期难以维护;
- 违反迪米特法则:客户端必须记住所有优惠类型字符串,强耦合;
- 违反合成复用:无任何代码复用,全是硬编码;
- 难以测试:一个方法包含所有逻辑,单元测试覆盖率极低;
- 协作成本高:多人开发时,极易出现代码冲突。
这就是企业级项目中必须用策略模式的核心原因:传统写法完全不符合架构设计规范,无法支撑业务快速迭代。
第四部分:策略模式 Java 代码实现(三层进阶:基础→优化→企业级)
我们以电商优惠结算为场景,分三个阶段实现策略模式,从基础版到 SpringBoot 企业级实战版,逐步优化,贴合真实项目开发。
阶段 1:基础标准版策略模式(核心原理)
严格遵循策略模式四大角色,实现最纯粹的策略模式。
步骤 1:定义抽象策略接口(Strategy)
定义优惠算法的公共契约,遵循接口隔离原则。
import java.math.BigDecimal;
/**
* 抽象优惠策略:定义所有优惠的统一接口
*/
public interface PromotionStrategy {
/**
* 计算优惠后价格
* @param originalPrice 商品原价
* @return 优惠后价格
*/
BigDecimal calculateDiscountPrice(BigDecimal originalPrice);
}
步骤 2:定义具体策略类(ConcreteStrategy)
每个策略类只实现一种算法,遵循单一职责原则。
// 1. 无优惠策略
public class NonePromotion implements PromotionStrategy {
@Override
public BigDecimal calculateDiscountPrice(BigDecimal originalPrice) {
return originalPrice;
}
}
// 2. 满减策略:满100减20
public class FullReductionPromotion implements PromotionStrategy {
@Override
public BigDecimal calculateDiscountPrice(BigDecimal originalPrice) {
if (originalPrice.compareTo(new BigDecimal("100")) >= 0) {
return originalPrice.subtract(new BigDecimal("20"));
}
return originalPrice;
}
}
// 3. 折扣策略:8折
public class DiscountPromotion implements PromotionStrategy {
@Override
public BigDecimal calculateDiscountPrice(BigDecimal originalPrice) {
return originalPrice.multiply(new BigDecimal("0.8"));
}
}
// 4. 优惠券策略:减30
public class CouponPromotion implements PromotionStrategy {
@Override
public BigDecimal calculateDiscountPrice(BigDecimal originalPrice) {
return originalPrice.subtract(new BigDecimal("30"));
}
}
步骤 3:定义上下文类(Context)
持有策略对象,对外提供统一调用入口,屏蔽客户端直接访问策略,遵循迪米特法则+合成复用原则。
import java.math.BigDecimal;
/**
* 优惠上下文:负责调度优惠策略
*/
public class PromotionContext {
// 组合持有抽象策略对象(合成复用原则)
private final PromotionStrategy promotionStrategy;
// 构造器注入策略
public PromotionContext(PromotionStrategy promotionStrategy) {
this.promotionStrategy = promotionStrategy;
}
// 对外统一调用入口
public BigDecimal executeCalculate(BigDecimal originalPrice) {
return promotionStrategy.calculateDiscountPrice(originalPrice);
}
}
步骤 4:客户端调用(Client)
面向接口编程,遵循依赖倒置原则。
import java.math.BigDecimal;
public class Client {
public static void main(String[] args) {
BigDecimal originalPrice = new BigDecimal("200");
// 1. 使用无优惠策略
PromotionContext context1 = new PromotionContext(new NonePromotion());
System.out.println("无优惠:" + context1.executeCalculate(originalPrice));
// 2. 使用满减策略
PromotionContext context2 = new PromotionContext(new FullReductionPromotion());
System.out.println("满减优惠:" + context2.executeCalculate(originalPrice));
// 3. 动态切换折扣策略
PromotionContext context3 = new PromotionContext(new DiscountPromotion());
System.out.println("折扣优惠:" + context3.executeCalculate(originalPrice));
}
}
基础版总结
- 彻底分离算法定义与使用;
- 每个策略类职责单一;
- 客户端面向接口编程,解耦具体实现。
阶段 2:优化版:工厂模式 + 策略模式(消除客户端判断)
基础版的缺陷:客户端需要手动创建策略对象,仍存在简单的判断逻辑。
优化方案:结合简单工厂模式,将策略对象的创建封装到工厂中,客户端只需传入类型,工厂自动返回对应策略。
新增:策略工厂类
/**
* 优惠策略工厂:封装策略对象创建
*/
public class PromotionStrategyFactory {
// 私有化构造器,禁止实例化
private PromotionStrategyFactory() {}
/**
* 根据类型获取优惠策略
*/
public static PromotionStrategy getStrategy(String type) {
return switch (type) {
case "NONE" -> new NonePromotion();
case "FULL_REDUCTION" -> new FullReductionPromotion();
case "DISCOUNT" -> new DiscountPromotion();
case "COUPON" -> new CouponPromotion();
default -> throw new IllegalArgumentException("不支持的优惠类型");
};
}
}
优化后客户端调用
public class Client {
public static void main(String[] args) {
BigDecimal originalPrice = new BigDecimal("200");
// 客户端只需传入类型,无需创建策略对象
PromotionContext context = new PromotionContext(PromotionStrategyFactory.getStrategy("FULL_REDUCTION"));
System.out.println("工厂+策略模式:满减优惠 = " + context.executeCalculate(originalPrice));
}
}
优化版优势
- 消除客户端的策略创建逻辑;
- 集中管理所有策略,便于维护;
- 进一步降低客户端与策略的耦合。
阶段 3:企业级版:SpringBoot 整合策略模式(真实项目落地)
在微服务项目中,我们不会手动创建对象,而是通过Spring IOC 容器管理 Bean,结合自定义注解实现策略的自动注册与发现,这是互联网公司最常用的落地方式。
步骤 1:SpringBoot 项目依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
步骤 2:自定义策略类型注解
标识策略类对应的业务类型,实现自动绑定。
import java.lang.annotation.*;
/**
* 自定义优惠策略注解:标识策略类型
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component // 交给Spring管理
public @interface PromotionType {
/**
* 优惠类型:NONE/FULL_REDUCTION/DISCOUNT/COUPON
*/
String value();
}
步骤 3:改造具体策略类(添加注解)
// 无优惠策略
@PromotionType("NONE")
public class NonePromotion implements PromotionStrategy {
@Override
public BigDecimal calculateDiscountPrice(BigDecimal originalPrice) {
return originalPrice;
}
}
// 满减策略
@PromotionType("FULL_REDUCTION")
public class FullReductionPromotion implements PromotionStrategy {
@Override
public BigDecimal calculateDiscountPrice(BigDecimal originalPrice) {
if (originalPrice.compareTo(new BigDecimal("100")) >= 0) {
return originalPrice.subtract(new BigDecimal("20"));
}
return originalPrice;
}
}
// 折扣策略、优惠券策略同理添加注解
步骤 4:Spring 策略工厂(自动加载所有策略)
通过 Spring 上下文获取所有标注@PromotionType的 Bean,自动注册到 Map 中。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@Component
public class SpringPromotionStrategyFactory {
@Autowired
private ApplicationContext applicationContext;
// 存储所有策略:key=优惠类型,value=策略对象
private static final Map<String, PromotionStrategy> STRATEGY_MAP = new ConcurrentHashMap<>();
/**
* 项目启动时,自动加载所有优惠策略
*/
@PostConstruct
public void initStrategies() {
// 获取所有标注@PromotionType的Bean
Map<String, Object> beans = applicationContext.getBeansWithAnnotation(PromotionType.class);
for (Object bean : beans.values()) {
if (!(bean instanceof PromotionStrategy)) continue;
// 获取注解中的类型
PromotionType annotation = bean.getClass().getAnnotation(PromotionType.class);
String type = annotation.value();
// 存入Map
STRATEGY_MAP.put(type, (PromotionStrategy) bean);
}
}
/**
* 获取策略
*/
public PromotionStrategy getStrategy(String type) {
PromotionStrategy strategy = STRATEGY_MAP.get(type);
if (strategy == null) {
throw new IllegalArgumentException("不支持的优惠类型:" + type);
}
return strategy;
}
}
步骤 5:上下文类(交给 Spring 管理)
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
@Component
public class PromotionContext {
@Autowired
private SpringPromotionStrategyFactory strategyFactory;
// 动态计算优惠价格
public BigDecimal calculatePrice(BigDecimal originalPrice, String type) {
PromotionStrategy strategy = strategyFactory.getStrategy(type);
return strategy.calculateDiscountPrice(originalPrice);
}
}
步骤 6:Controller 接口(对外提供服务)
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.math.BigDecimal;
@RestController
public class PromotionController {
@Autowired
private PromotionContext promotionContext;
@GetMapping("/calculate")
public String calculate(@RequestParam BigDecimal price, @RequestParam String type) {
BigDecimal result = promotionContext.calculatePrice(price, type);
return "原价:" + price + ",优惠后价格:" + result;
}
}
企业级版核心优势
- 完全基于 Spring IOC 管理,无手动创建对象;
- 新增策略零代码修改:只需新增策略类 + 添加
@PromotionType注解; - 自动注册策略,无需维护工厂代码;
- 适配微服务、分布式系统,生产环境直接可用。
第五部分:策略模式与七大设计原则深度结合(架构核心)
这是策略模式成为架构师首选模式的核心原因:它完美满足所有七大设计原则,我们结合上面的代码逐一验证:
1. 契合单一职责原则(SRP)
- 每个具体策略类(如
FullReductionPromotion)只实现一种优惠算法,职责单一; - 上下文类
PromotionContext只负责策略调度,不实现任何算法; - 策略工厂只负责策略创建,分工明确,高内聚。
2. 契合开闭原则(OCP)
- 扩展开放:新增秒杀优惠,只需创建
SeckillPromotion类 + 添加@PromotionType("SECKILL")注解; - 修改关闭:原有接口、上下文、工厂、业务代码完全不改动;
- 彻底避免修改原有代码带来的 bug 风险。
3. 契合里氏替换原则(LSP)
- 所有策略类都实现
PromotionStrategy接口,严格遵循接口契约; - 客户端使用接口引用,可无缝替换任意策略实现类,无任何异常;
- 子类不破坏父类契约,符合继承 / 实现规范。
4. 契合依赖倒置原则(DIP)
- 高层模块(Controller、Context)依赖抽象接口
PromotionStrategy,不依赖具体策略类; - 低层策略类依赖抽象接口实现自己的逻辑;
- 彻底实现面向接口编程,解耦高层与低层。
5. 契合接口隔离原则(ISP)
- 抽象策略接口只定义一个核心方法
calculateDiscountPrice,无任何冗余方法; - 实现类只需实现必要方法,无需实现无用接口;
- 接口精简单一,符合最小接口原则。
6. 契合迪米特法则(LOD)
- 客户端(Controller)只与上下文类交互,完全不知道具体策略的存在;
- 策略的创建、调度、执行全部封装在内部,客户端无感知;
- 类之间耦合度极低,最少知道。
7. 契合合成复用原则(CRP)
- 上下文类通过组合持有策略接口对象,而非继承策略类;
- 组合是弱耦合,可动态切换策略;
- 避免继承带来的强耦合、层级混乱问题。
第六部分:策略模式在企业级项目中的实战应用场景(全覆盖)
策略模式是业务多变场景的万能解,在 Java 企业级开发中应用无处不在,以下是 11 个高频实战场景,每个场景都贴合真实业务:
场景 1:电商支付渠道策略(最经典)
业务需求
支持微信支付、支付宝、银联、云闪付、数字人民币多种支付方式,用户可自由切换。
策略模式落地
- 抽象策略:
PayStrategy(支付、退款接口); - 具体策略:
WechatPayStrategy、AlipayStrategy、UnionPayStrategy; - 上下文:
PayContext; - 扩展:新增支付方式,只需加策略类,无代码改动。
场景 2:电商营销促销策略
业务需求
满减、折扣、优惠券、秒杀、拼团、预售、会员价等 10 + 种优惠方式。
策略模式落地
本文实战案例,完美适配,支持营销活动快速上线。
场景 3:文件解析 / 导出策略
业务需求
解析 Excel、CSV、PDF、Word 文件;导出 Excel、CSV、PDF 格式报表。
策略模式落地
- 抽象策略:
FileParseStrategy、FileExportStrategy; - 具体策略:
ExcelParseStrategy、PdfExportStrategy; - 优势:新增文件格式,零改动扩展。
场景 4:用户登录认证策略
业务需求
密码登录、短信验证码、微信 OAuth2.0、支付宝登录、人脸登录。
策略模式落地
- 抽象策略:
LoginStrategy; - 具体策略:
PasswordLoginStrategy、SmsLoginStrategy; - 适配多端登录,灵活切换认证方式。
场景 5:分布式缓存策略
业务需求
本地缓存(Caffeine)、Redis 缓存、Memcached 缓存动态切换。
策略模式落地
- 抽象策略:
CacheStrategy; - 具体策略:
LocalCacheStrategy、RedisCacheStrategy; - 适配不同业务场景的缓存需求。
场景 6:数据加密解密策略
业务需求
AES 对称加密、RSA 非对称加密、MD5/SHA 摘要加密、国密 SM4。
策略模式落地
- 抽象策略:
EncryptStrategy; - 具体策略:
AesEncryptStrategy、RsaEncryptStrategy; - 金融、支付系统必备。
场景 7:JDK 原生线程池拒绝策略
业务需求
线程池满时,4 种拒绝策略:
AbortPolicy:抛出异常(默认);CallerRunsPolicy:调用者线程执行;DiscardPolicy:丢弃任务;DiscardOldestPolicy:丢弃最老任务。
策略模式落地
JDK 线程池直接使用策略模式,RejectedExecutionHandler是抽象策略,4 个实现类是具体策略。
场景 8:消息推送策略
业务需求
短信推送、APP 推送、微信公众号推送、邮件推送、钉钉推送。
策略模式落地
- 抽象策略:
PushStrategy; - 具体策略:
SmsPushStrategy、EmailPushStrategy; - 灵活切换推送渠道。
场景 9:支付风控策略
业务需求
低风险直接通过、中风险短信验证、高风险拦截订单。
策略模式落地
- 抽象策略:
RiskControlStrategy; - 具体策略:
LowRiskStrategy、HighRiskStrategy; - 金融支付核心场景。
场景 10:数据排序 / 筛选策略
业务需求
商品按价格、销量、评分、创建时间排序。
策略模式落地
JDK Comparator接口就是策略模式,Collections.sort(list, comparator)动态切换排序规则。
场景 11:报表生成策略
业务需求
销售报表、库存报表、用户报表、财务报表,不同报表生成逻辑不同。
策略模式落地
- 抽象策略:
ReportStrategy; - 具体策略:
SalesReportStrategy、StockReportStrategy; - 企业后台管理系统必备。
第七部分:策略模式带来的核心优势(架构师必知)
策略模式是企业级开发的刚需设计模式,相比传统if-else写法,拥有 10 大核心优势:
1. 彻底解耦:算法定义与算法使用分离
策略模式将可变的算法与不变的调用逻辑彻底分离,算法的修改不影响调用方,调用方的变更不影响算法实现,符合关注点分离架构思想。
2. 极致扩展:完美遵循开闭原则
新增算法零修改原有代码,只需新增策略实现类,完全适配业务快速迭代,是微服务、电商、金融等多变业务的最佳选择。
3. 消除冗余:告别臃肿的 if-else/switch
传统业务中,百行级别的条件判断是常态,策略模式将分支拆分为独立类,代码简洁到极致,可读性提升 10 倍。
4. 高可维护性:职责单一,代码清晰
每个策略类只做一件事,代码量极少,后期维护、排查 bug、修改逻辑都极其简单,降低运维成本。
5. 灵活替换:运行时动态切换算法
通过上下文的setStrategy方法,可在运行时动态切换算法,无需重启服务,适配实时业务需求。
6. 高可测试性:单元测试极简
每个策略类独立存在,可单独编写单元测试,测试覆盖率 100%,避免传统写法整体测试的复杂性。
7. 规范架构:强制遵循七大设计原则
策略模式从设计层面约束开发者写出高质量代码,避免烂代码,提升团队整体架构水平。
8. 低耦合:客户端无感知算法细节
客户端只与上下文交互,无需知道具体算法实现,符合迪米特法则,系统耦合度极低。
9. 高效协作:多人开发无冲突
不同开发者负责不同策略类,代码完全隔离,无合并冲突,提升团队开发效率。
10. 生产级可用:主流框架原生支持
Spring、SpringBoot、JDK、MyBatis 等主流框架原生使用策略模式,与生态完美融合,生产环境稳定可靠。
第八部分:策略模式注意事项与优化方案
1. 策略类膨胀问题
当算法过多时,会产生大量策略类(类爆炸)。
优化方案:
- 结合枚举 + 策略合并简单策略;
- 抽象策略类抽取公共代码,减少重复;
- Spring 自动注册策略,集中管理。
2. 避免过度设计
- 简单固定算法(无扩展需求):无需使用策略模式;
- 只有 1-2 种算法:直接硬编码即可,防止过度设计增加复杂度。
3. 公共代码抽取
将所有策略的公共逻辑抽取到抽象策略类中,具体策略继承抽象类,减少重复代码。
4. 策略选择逻辑集中
策略的选择逻辑统一放在工厂 / 上下文中,绝不分散在客户端,便于维护。
第九部分:策略模式在主流框架源码中的应用
策略模式是框架设计的标配,以下是 Java 生态中最经典的应用:
1. JDK Comparator 接口
java.util.Comparator是抽象策略,自定义比较器是具体策略,Collections.sort(List, Comparator)是上下文调用。
2. JDK 线程池拒绝策略
RejectedExecutionHandler(抽象策略) + 4 个实现类(具体策略) + ThreadPoolExecutor(上下文)。
3. Spring BeanNameGenerator
Bean 名称生成策略,支持默认生成、自定义生成,完美使用策略模式。
4. Spring MVC HandlerMapping
请求映射策略,RequestMappingHandlerMapping、BeanNameUrlHandlerMapping是具体策略。
5. MyBatis 日志模块
Log接口(抽象策略),适配 SLF4J、Log4j、Console 等日志框架(具体策略)。
第十部分:策略模式与相似设计模式的区分
1. 策略模式 VS 模板方法模式
- 策略模式:组合 / 委托,算法完全独立,无固定流程;
- 模板方法:继承,固定算法流程,仅开放部分步骤自定义。
2. 策略模式 VS 状态模式
- 策略模式:算法切换无状态依赖,由客户端主动指定;
- 状态模式:行为切换由状态自动触发,有状态依赖。
3. 策略模式 VS 适配器模式
- 策略模式:替换算法,功能相同,实现不同;
- 适配器模式:兼容接口,功能不同,适配调用。
总结
策略模式是 Java 架构师必须掌握的核心行为型设计模式,它以七大设计原则为基石,彻底解决了算法多变、代码臃肿、耦合度高的行业痛点。
本文从基础理论→代码实现→企业级 SpringBoot 实战→业务场景→框架源码全维度拆解策略模式,核心价值总结:
- 核心思想:分离算法定义与使用,封装可变,开放扩展;
- 设计合规:完美契合七大设计原则,是架构设计的标杆;
- 业务价值:消除 if-else,支持灵活扩展,适配所有多变业务场景;
- 生产落地:SpringBoot 整合方案可直接用于微服务、电商、金融等生产项目。
在实际开发中,只要遇到同一行为多种实现的场景,优先选择策略模式,它能让你的代码从「臃肿混乱」变为「优雅可扩展」,是架构师提升代码质量的核心武器。
浙公网安备 33010602011771号