移动端访问不佳,请访问我的个人博客
设计模式学习的demo地址,欢迎大家学习交流
策略模式
策略模式定义了算法家族,分别封装起来,让它们之间可以相互替换,此模式让算法的变化,不会影响到使用算法的客户。
策略模式的组成
- 抽象策略角色(Strategy): 策略类,通常由一个接口或者抽象类实现。
- 具体策略角色(ConcreteStrategy):包装了相关的算法和行为。
- 环境角色(Context):持有一个策略类的引用,最终给客户端调用。
策略模式的基本实现
上图是最基本的装饰模式的结构图,下面将用Swift代码来实现一个基本策略模式:
// 策略类,定义所有支持 的算法的公共接口@H_404_27@
protocol Strategy {
func AlgorithmInterface()
}
// 具体策略类,封装了具体的算法或行为,继承于Strategy@H_404_27@
class@H_404_27@ ConcreteStrategyA@H_404_27@: Strategy@H_404_27@ {@H_404_27@
func AlgorithmInterface() {
print("ConcreteStrategyA"@H_404_27@)
}
}
class@H_404_27@ ConcreteStrategyB@H_404_27@: Strategy@H_404_27@ {@H_404_27@
func AlgorithmInterface() {
print("ConcreteStrategyB"@H_404_27@)
}
}
class@H_404_27@ ConcreteStrategyC@H_404_27@: Strategy@H_404_27@ {@H_404_27@
func AlgorithmInterface() {
print("ConcreteStrategyC"@H_404_27@)
}
}
// Context上下文,用一个 ConcreteStrategy来配置,维护一个对Strategy对象的引用@H_404_27@
class@H_404_27@ Context@H_404_27@ {@H_404_27@
var@H_404_27@ strategy: Strategy?
func ContextInterface() {
strategy?.AlgorithmInterface()
}
}
以上代码是最简单的策略模式的实现过程,定义了一个Strategy
的算法族,通过它的子类可以实现算法(AlgorithmInterface
)的替换,而不会影响到客户端。
用策略模式解决实际问题(商场打折)
我们知道在商场中一般有很多打折优惠方案,类似这种问题就可以用策略模式来解决,打折不同的方案就相当于不同的策略(ConcreteStrategy
),然后用一个Context
类来实现不同算法的切换,下面是商场打折策略模式的实现于UML
图:
以上是一个简单的商场收银系统,CashNormal
为普通收费子类,CashRebate
为打折收费子类,CashReturn
为返利收费子类,下面是代码的实现过程:
import@H_404_27@ Foundation
// 定义一个收费的策略接口@H_404_27@
protocol CashSuper {
func acceptCash(money: Double) -> @H_404_27@Double
}
// 普通收费子类@H_404_27@
class CashNormal: CashSuper {
// 正常原价返回@H_404_27@
func acceptCash(money: Double) -> @H_404_27@Double {
return@H_404_27@ money
}
}
// 打折收费子类@H_404_27@
class CashRebate: CashSuper {
// 折扣率@H_404_27@
private@H_404_27@ var@H_404_27@ moneyRebate: Double =@H_404_27@ 1.0@H_404_27@
init(moneyRebate: Double) {
self@H_404_27@.@H_404_27@moneyRebate =@H_404_27@ moneyRebate
}
func acceptCash(money: Double) -> @H_404_27@Double {
return@H_404_27@ money*@H_404_27@moneyRebate
}
}
// 返利收费子类@H_404_27@
class CashReturn: CashSuper {
// 返利要求@H_404_27@
private@H_404_27@ var@H_404_27@ moneyCondition: Double =@H_404_27@ 0@H_404_27@
// 返多少@H_404_27@
private@H_404_27@ var@H_404_27@ moneyReturn: Double =@H_404_27@ 0@H_404_27@
init(moneyCondition: Double,moneyReturn: Double) {
self@H_404_27@.@H_404_27@moneyCondition =@H_404_27@ moneyCondition
self@H_404_27@.@H_404_27@moneyReturn =@H_404_27@ moneyReturn
}
func acceptCash(money: Double) -> @H_404_27@Double {
var@H_404_27@ result =@H_404_27@ money
if@H_404_27@ money >=@H_404_27@ moneyCondition {
result =@H_404_27@ money -@H_404_27@ floor(money /@H_404_27@ moneyCondition) *@H_404_27@ moneyReturn
}
return@H_404_27@ result
}
}
// context类@H_404_27@
class CashContext {
private@H_404_27@ var@H_404_27@ cs: CashSuper?@H_404_27@
// 通过枚举判断使用哪种方式@H_404_27@
init(style: CashStyle) {
switch style {
case@H_404_27@ .@H_404_27@normal:
cs =@H_404_27@ CashNormal()
case@H_404_27@ .@H_404_27@rebate(moneyRebate: let@H_404_27@ money):
cs =@H_404_27@ CashRebate(moneyRebate: money)
case@H_404_27@ .@H_404_27@return@H_404_27@(moneyCondition: let@H_404_27@ moneyCondition,moneyReturn: let@H_404_27@ moneyReturn):
cs =@H_404_27@ CashReturn(moneyCondition: moneyCondition,moneyReturn: moneyReturn)
}
}
func getResult(money: Double) -> @H_404_27@Double {
return@H_404_27@ cs?@H_404_27@.@H_404_27@acceptCash(money: money) ??@H_404_27@ 0@H_404_27@
}
}
// 优惠的枚举类型@H_404_27@
enum CashStyle {
case@H_404_27@ normal
case@H_404_27@ rebate(moneyRebate: Double)
case@H_404_27@ `return`@H_404_27@(moneyCondition: Double,moneyReturn: Double)
}
下面我们测试一下代码:
let@H_404_27@ money@H_404_27@: Double = 300@H_404_27@
// 普通
let@H_404_27@ normal = CashContext(style@H_404_27@: .normal)
//@H_404_27@ 打7@H_404_27@折
let@H_404_27@ rebate = CashContext(style@H_404_27@: .rebate(moneyRebate@H_404_27@: 0.7@H_404_27@))
//@H_404_27@ 满一百返20@H_404_27@
let@H_404_27@ `return@H_404_27@@H_404_27@` = CashContext(style@H_404_27@: .return@H_404_27@(moneyCondition@H_404_27@: 100@H_404_27@,moneyReturn@H_404_27@: 20@H_404_27@))
print@H_404_27@("普通: \(normal.getResult(money: money))"@H_404_27@)
print@H_404_27@("打7折: \(rebate.getResult(money: money))"@H_404_27@)
print@H_404_27@("满一百返20: \(`return`.getResult(money: money))"@H_404_27@)
下面是执行的结果:
普通: 300.0 打7折: 210.0 满一百返20: 240.0
策略模式总结
我们可以理解为策略就是用来封装算法,但在实践过程中不用那么死板,可以用来封装几乎任何类型的规则,只要在分析过程中听到需要在不同时间应用不同的业务规则,就可以考虑使用策略模式处理这种变化的可能性。
以上是我对于策略模式的理解,如果有不对的地方欢迎大家交流,最后谢谢大家的阅读~~