策略模式最适合解决同一问题有多种算法实现且需动态切换的场景,如折扣计算;其核心角色包括定义统一方法的策略接口、专注单一逻辑的具体策略类、以及持有策略引用并负责调用的上下文。

策略模式最适合解决“同一问题有多种算法实现,且需要动态切换”的场景。折扣计算正是典型代表:不同用户类型、活动规则、商品类别对应不同折扣逻辑,硬编码在 if-else 里会导致每次新增策略都要改主逻辑,违反开闭原则。
明确三个核心角色
先理清职责分工,避免混淆:
-
折扣策略接口(Strategy):定义统一方法,比如
apply(double originalPrice),所有具体折扣算法必须实现它 -
具体折扣类(Concrete Strategy):每个类只专注一种折扣逻辑,例如
FixedAmountDiscount(减5元)、PercentageDiscount(打8折)、ThresholdDiscount(满300减50) -
折扣上下文(Context):持有当前策略引用,提供
setStrategy()和calculate()方法,不关心具体怎么算,只负责调用
用 Spring 实现自动装配与动态选择
真实项目中不会手动 new 策略对象,而是靠 Spring 容器管理:
- 给每个具体策略类加上
@Component注解,并按约定命名 Bean(如fixedDiscount、percentageDiscount) - 在上下文类中注入
Map,Key 可以是枚举值或策略编码(如"FIXED"、"PERCENT") - 根据业务参数(如优惠券类型、用户等级)查出对应策略 Bean,直接调用
支持运行时策略组合与降级
单一折扣不够用?电商常需叠加(如“满减+会员折”),这时可扩展 Context:
- 让 Context 接收多个策略,按顺序执行(如先满减再打折),结果链式传递
- 增加兜底机制:当某策略因参数异常无法执行时,自动 fallback 到默认策略(如无折扣)
- 策略本身也可带校验逻辑,比如
ThresholdDiscount.apply()先判断是否达门槛,不满足则返回原价
避免常见陷阱
写得像策略模式,但没真正解耦,容易踩坑:
- 不要在策略类里写数据库查询或远程调用——策略应是纯计算,外部数据由 Context 或 Service 提前准备好传入
- 别把策略对象当成单例全局共享——如果策略内部有状态(如缓存计数),要用 prototype 作用域或每次新建
- 策略命名要反映业务语义,而不是技术实现,比如用
VipEightFiveDiscount而不是MultipliedBy085Strategy











