什么是策略模式?
策略模式(Strategy Pattern) 是一种行为设计模式,它定义了一系列算法,并将每个算法封装起来,使它们可以相互替换。策略模式让算法的变化独立于使用算法的客户端。
简单来说:定义策略家族,让客户端自由选择。
现实世界类比
想象你去餐厅吃饭:
- 策略接口:点菜这个行为
- 具体策略:中餐、西餐、日料等不同菜系
- 上下文:餐厅(提供点菜环境)
- 客户端:你(根据心情选择今天吃什么)
模式结构
1classDiagram 2 class Strategy { 3 <<interface>> 4 +executeStrategy() void 5 } 6 7 class ConcreteStrategyA { 8 +executeStrategy() void 9 } 10 11 class ConcreteStrategyB { 12 +executeStrategy() void 13 } 14 15 class Context { 16 -strategy: Strategy 17 +setStrategy(Strategy) void 18 +execute() void 19 } 20 21 Strategy <|.. ConcreteStrategyA 22 Strategy <|.. ConcreteStrategyB 23 Context --> Strategy
代码示例:支付系统设计
问题场景
我们需要实现一个支付系统,支持多种支付方式(支付宝、微信、银行卡),并且未来可能添加新的支付方式。
传统实现(不推荐)
kotlin
复制
1class PaymentService { 2 fun pay(amount: Double, paymentType: String) { 3 when (paymentType) { 4 "alipay" -> { 5 // 复杂的支付宝支付逻辑 6 println("支付宝支付:$amount 元") 7 // 几十行代码... 8 } 9 "wechat" -> { 10 // 复杂的微信支付逻辑 11 println("微信支付:$amount 元") 12 // 几十行代码... 13 } 14 "bank" -> { 15 // 复杂的银行卡支付逻辑 16 println("银行卡支付:$amount 元") 17 // 几十行代码... 18 } 19 else -> throw IllegalArgumentException("不支持的支付方式") 20 } 21 } 22} 23 24// 使用示例 25val service = PaymentService() 26service.pay(100.0, "alipay") // 添加新支付方式需要修改这个类!
问题分析:
- ❌ 违反开闭原则:添加新支付方式需要修改现有代码
- ❌ 职责过重:一个类包含所有支付逻辑
- ❌ 难以测试:支付逻辑耦合在一起
策略模式实现(推荐)
1. 定义策略接口
kotlin
复制
1interface PaymentStrategy { 2 fun pay(amount: Double): Boolean 3 fun getStrategyName(): String 4}
2. 实现具体策略
kotlin
复制
1// 支付宝支付策略 2class AlipayStrategy : PaymentStrategy { 3 override fun pay(amount: Double): Boolean { 4 println("调用支付宝API,支付金额:$amount 元") 5 // 实际的支付宝支付逻辑 6 return true // 支付成功 7 } 8 9 override fun getStrategyName() = "支付宝" 10} 11 12// 微信支付策略 13class WechatPayStrategy : PaymentStrategy { 14 override fun pay(amount: Double): Boolean { 15 println("调用微信支付API,支付金额:$amount 元") 16 // 实际的微信支付逻辑 17 return true 18 } 19 20 override fun getStrategyName() = "微信支付" 21} 22 23// 银行卡支付策略 24class BankCardStrategy : PaymentStrategy { 25 override fun pay(amount: Double): Boolean { 26 println("调用银联API,支付金额:$amount 元") 27 // 实际的银行卡支付逻辑 28 return true 29 } 30 31 override fun getStrategyName() = "银行卡" 32}
3. 支付上下文
kotlin
复制
1class PaymentContext { 2 private var strategy: PaymentStrategy? = null 3 4 fun setPaymentStrategy(strategy: PaymentStrategy) { 5 this.strategy = strategy 6 println("支付方式切换为:${strategy.getStrategyName()}") 7 } 8 9 fun executePayment(amount: Double): Boolean { 10 return strategy?.pay(amount) ?: throw IllegalStateException("请先设置支付策略") 11 } 12 13 fun getCurrentStrategy() = strategy?.getStrategyName() ?: "未设置" 14}
4. 客户端使用
kotlin
复制
1fun main() { 2 val context = PaymentContext() 3 4 // 用户选择支付宝支付 5 context.setPaymentStrategy(AlipayStrategy()) 6 context.executePayment(100.0) 7 8 // 用户切换为微信支付 9 context.setPaymentStrategy(WechatPayStrategy()) 10 context.executePayment(200.0) 11 12 // 动态根据条件选择策略 13 val userPreference = getUserPaymentPreference() // 模拟获取用户偏好 14 val strategy = when (userPreference) { 15 "alipay" -> AlipayStrategy() 16 "wechat" -> WechatPayStrategy() 17 "bank" -> BankCardStrategy() 18 else -> AlipayStrategy() // 默认策略 19 } 20 21 context.setPaymentStrategy(strategy) 22 context.executePayment(150.0) 23} 24 25fun getUserPaymentPreference() = "wechat" // 模拟数据
更复杂的实战案例:折扣策略系统
业务需求
电商平台需要支持多种折扣策略:
- 普通折扣(固定比例)
- 满减折扣(满100减20)
- 会员折扣(根据会员等级)
- 季节性折扣(特定时间段)
策略模式实现
kotlin
复制
1// 折扣策略接口 2interface DiscountStrategy { 3 fun calculateDiscount(originalPrice: Double): Double 4 fun getStrategyDescription(): String 5} 6 7// 具体策略实现 8class PercentageDiscountStrategy(private val discountRate: Double) : DiscountStrategy { 9 override fun calculateDiscount(originalPrice: Double): Double { 10 return originalPrice * discountRate 11 } 12 13 override fun getStrategyDescription() = "${(discountRate * 100)}% 折扣" 14} 15 16class FullReductionStrategy(private val fullAmount: Double, private val reduction: Double) : DiscountStrategy { 17 override fun calculateDiscount(originalPrice: Double): Double { 18 return if (originalPrice >= fullAmount) reduction else 0.0 19 } 20 21 override fun getStrategyDescription() = "满 $fullAmount 减 $reduction" 22} 23 24class MemberDiscountStrategy(private val memberLevel: String) : DiscountStrategy { 25 private val discountRates = mapOf( 26 "gold" to 0.8, // 金卡8折 27 "silver" to 0.9, // 银卡9折 28 "normal" to 0.95 // 普通卡95折 29 ) 30 31 override fun calculateDiscount(originalPrice: Double): Double { 32 val rate = discountRates[memberLevel] ?: 1.0 33 return originalPrice * (1 - rate) 34 } 35 36 override fun getStrategyDescription() = "${memberLevel}会员折扣" 37} 38 39// 折扣上下文 40class DiscountContext { 41 private var strategy: DiscountStrategy = PercentageDiscountStrategy(1.0) // 默认无折扣 42 43 fun setDiscountStrategy(strategy: DiscountStrategy) { 44 this.strategy = strategy 45 } 46 47 fun calculateFinalPrice(originalPrice: Double): Double { 48 val discount = strategy.calculateDiscount(originalPrice) 49 val finalPrice = originalPrice - discount 50 51 println("原价:$originalPrice") 52 println("折扣策略:${strategy.getStrategyDescription()}") 53 println("折扣金额:$discount") 54 println("最终价格:$finalPrice") 55 println("---") 56 57 return finalPrice 58 } 59} 60 61// 使用示例 62fun main() { 63 val context = DiscountContext() 64 val originalPrice = 200.0 65 66 // 测试不同折扣策略 67 context.setDiscountStrategy(PercentageDiscountStrategy(0.8)) // 8折 68 context.calculateFinalPrice(originalPrice) 69 70 context.setDiscountStrategy(FullReductionStrategy(100.0, 20.0)) // 满100减20 71 context.calculateFinalPrice(originalPrice) 72 73 context.setDiscountStrategy(MemberDiscountStrategy("gold")) // 金卡会员 74 context.calculateFinalPrice(originalPrice) 75}
策略模式的优点
✅ 开闭原则
添加新策略无需修改现有代码:
kotlin
复制
1// 新增一个节日折扣策略 2class FestivalDiscountStrategy : DiscountStrategy { 3 override fun calculateDiscount(originalPrice: Double): Double { 4 return originalPrice * 0.7 // 节日7折 5 } 6 7 override fun getStrategyDescription() = "节日特惠折扣" 8} 9 10// 使用新策略(无需修改现有代码) 11context.setDiscountStrategy(FestivalDiscountStrategy())
✅ 消除条件判断
用多态替代复杂的条件语句,代码更清晰。
✅ 易于测试
每个策略可以独立测试:
kotlin
复制
1@Test 2fun testPercentageDiscount() { 3 val strategy = PercentageDiscountStrategy(0.8) 4 assertEquals(80.0, strategy.calculateDiscount(100.0)) 5}
✅ 算法复用
策略可以在不同上下文中复用。
适用场景
🎯 推荐使用策略模式的情况:
- 多种算法变体:一个功能有多个实现版本
- 避免条件爆炸:复杂的if-else或switch-case语句
- 算法需要独立变化:不同算法可能独立演化和替换
- 客户端需要灵活选择:运行时动态切换算法
🚫 不适用的情况:
- 算法很少变化:如果算法基本固定,过度设计反而复杂
- 客户端直接调用简单算法:如果算法很简单,直接调用即可
- 算法间差异很小:如果算法基本相同,用参数控制更简单
与其他模式的关系
🔄 策略模式 vs 状态模式
- 策略模式:客户端主动选择算法
- 状态模式:状态自动转换,客户端不感知状态变化
🔄 策略模式 vs 工厂模式
- 策略模式:关注算法的选择和替换
- 工厂模式:关注对象的创建和初始化
- 经常结合使用:工厂创建策略对象
Kotlin 的优化实现
利用 Kotlin 的语言特性,可以写出更简洁的策略模式:
使用函数类型
kotlin
复制
1typealias DiscountStrategy = (Double) -> Double 2 3val percentageDiscount: DiscountStrategy = { price -> price * 0.8 } 4val fullReductionDiscount: DiscountStrategy = { price -> if (price > 100) price - 20 else price } 5 6class DiscountCalculator(private var strategy: DiscountStrategy = { it }) { 7 fun setStrategy(newStrategy: DiscountStrategy) { 8 strategy = newStrategy 9 } 10 11 fun calculate(price: Double) = strategy(price) 12} 13 14// 使用 15val calculator = DiscountCalculator(percentageDiscount) 16println(calculator.calculate(100.0)) // 80.0
使用密封类
kotlin
复制
1sealed class DiscountStrategy { 2 object NoDiscount : DiscountStrategy() 3 data class Percentage(val rate: Double) : DiscountStrategy() 4 data class FullReduction(val full: Double, val reduction: Double) : DiscountStrategy() 5 6 fun calculate(price: Double): Double = when (this) { 7 is NoDiscount -> price 8 is Percentage -> price * rate 9 is FullReduction -> if (price >= full) price - reduction else price 10 } 11}
总结
策略模式是应对算法变化的利器,它通过"封装变化"让系统更灵活。记住策略模式的核心思想:
找出代码中可能变化的部分,把它抽离出来,封装成可互换的策略。
在实际项目中,当您发现复杂的条件判断或经常需要添加新的算法变体时,就是使用策略模式的最佳时机。
《策略模式:让算法选择像点菜一样简单》 是转载文章,点击查看原文。

