策略模式用于算法的自由切换和扩展,分离算法的定义与实现。
- 好处:将不同的行为策略(Strategy)进行独立封装,与类在逻辑上解耦,即可以动态改变对象的行为
- 原则:抽取代码中变化的部分来实现一个接口,并提供多种实现类,即算法。调用方需要使用这个接口的时候,可以动态的选择这些实现类。算法的变化独立于使用算法的调用者,从而可以轻松的扩展与改变策略,实现对象的动态改变行为,符合OCP原则
Android中策略模式的应用有WebView设计,Animation中的Interpolator设计.....
例如电商应用中的商品价格计算
fun main(args: Array<String>) {
val price = 4500.0
val mContext = PriceStrategyContext(NormalPriceStrategy())
mContext.strategyMethod(price)
mContext.setStrategy(GoldPriceStrategy())
mContext.strategyMethod(price)
}
interface PriceStrategy {
/**
* 计价方法
*/
fun calculate(price: Double): Double
}
class NormalPriceStrategy : PriceStrategy {
override fun calculate(price: Double): Double {
println("普通用户的计价策略方法被访问")
return price
}
}
class GoldPriceStrategy : PriceStrategy {
override fun calculate(price: Double): Double {
println("黄金会员的计价策略方法被访问")
return 0.95 * price
}
}
class DiamondPriceStrategy : PriceStrategy {
override fun calculate(price: Double): Double {
println("钻石会员的计价策略方法被访问")
return 0.9 * price
}
}
/**
* 上下文环境,定义了 PriceStrategy 接口引用,在创建 PriceStrategyContext 实例时传入具体的策略类,
* 具体策略类调用策略方法。客户端创建 PriceStrategyContext 对象负责调用策略方法。
*/
class PriceStrategyContext() {
private var mPriceStrategy: PriceStrategy? = null
constructor(mPriceStrategy: PriceStrategy) : this() {
this.mPriceStrategy = mPriceStrategy
}
fun setStrategy(strategy: PriceStrategy?): PriceStrategyContext {
mPriceStrategy = strategy!!
return this
}
//持有算法方法
fun strategyMethod(price: Double) {
mPriceStrategy!!.calculate(price)
}
}
策略模式中的上下文环境 PriceStrategyContext 的职责是隔离客户端与策略类的耦合,无须关注具体的策略行为。上面示例中, PriceStrategyContext 的作用只是负责调度策略类的执行并获取结果,并没有完全起到隔离客户端与策略类的作用。
通过简单工厂模式将具体策略对象的创建与调用方进行隔离,也可通过策略枚举或者策略类的配置注入,将PriceStrategyContext中的具体策略类融合在一起,简化代码。
简单工厂
abstract class PriceStrategyFactory {
companion object {
inline operator fun <reified T : PriceStrategy> invoke(): PriceStrategy? {
var strategy: PriceStrategy? = null
try {
strategy = T::class.java.newInstance() as PriceStrategy
} catch (e: Exception) {
e.printStackTrace()
}
return strategy
}
}
}
枚举
fun main(args: Array<String>) {
PriceStrategy.GOLD.calculate(4500.0)
}
enum class PriceStrategy(var type: String) {
//
NORMAL("normal") {
override fun calculate(price: Double): Double {
println("普通用户的计价策略方法被访问")
return price
}
},
GOLD("gold") {
override fun calculate(price: Double): Double {
println("黄金会员的计价策略方法被访问")
return price * 0.95
}
},
DIAMOND("diamond") {
override fun calculate(price: Double): Double {
println("钻石会员的计价策略方法被访问")
return price * 0.9
}
};
fun setType(type: String): PriceStrategy {
this.type = type
return this
}
abstract fun calculate(price: Double): Double
}
高阶函数抽象算法
策略类仅仅是针对算法行为的一种抽象,Kotlin 中可以使用高阶函数替代。
fun main(args: Array<String>) {
PriceStrategyContext(4500.0, NormalPriceStrategy).calculate()
}
// 策略用val声明成lambda表达式
val NormalPriceStrategy = { price: Double -> price }
val GoldPriceStrategy = { price: Double -> price * 0.95 }
val DiamondPriceStrategy = { price: Double -> price * 0.9 }
class PriceStrategyContext(private val price: Double, private val priceStrategy: (Double) -> Double) {
//
fun calculate() = priceStrategy(price)
}
策略模式需要不停的在各个算法间切换,造成很多逻辑判断,我们可以配合使用一些其他的模式去消除。