策略模式用于算法的自由切換和擴展,分離算法的定義與實現(xiàn)。
- 好處:將不同的行為策略(Strategy)進行獨立封裝,與類在邏輯上解耦,即可以動態(tài)改變對象的行為
- 原則:抽取代碼中變化的部分來實現(xiàn)一個接口,并提供多種實現(xiàn)類,即算法。調(diào)用方需要使用這個接口的時候,可以動態(tài)的選擇這些實現(xiàn)類。算法的變化獨立于使用算法的調(diào)用者,從而可以輕松的擴展與改變策略,實現(xiàn)對象的動態(tài)改變行為,符合OCP原則
Android中策略模式的應(yīng)用有WebView設(shè)計,Animation中的Interpolator設(shè)計.....
例如電商應(yīng)用中的商品價格計算
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
}
}
/**
* 上下文環(huán)境,定義了 PriceStrategy 接口引用,在創(chuàng)建 PriceStrategyContext 實例時傳入具體的策略類,
* 具體策略類調(diào)用策略方法??蛻舳藙?chuàng)建 PriceStrategyContext 對象負責(zé)調(diào)用策略方法。
*/
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)
}
}
策略模式中的上下文環(huán)境 PriceStrategyContext 的職責(zé)是隔離客戶端與策略類的耦合,無須關(guān)注具體的策略行為。上面示例中, PriceStrategyContext 的作用只是負責(zé)調(diào)度策略類的執(zhí)行并獲取結(jié)果,并沒有完全起到隔離客戶端與策略類的作用。
通過簡單工廠模式將具體策略對象的創(chuàng)建與調(diào)用方進行隔離,也可通過策略枚舉或者策略類的配置注入,將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
}
高階函數(shù)抽象算法
策略類僅僅是針對算法行為的一種抽象,Kotlin 中可以使用高階函數(shù)替代。
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)
}
策略模式需要不停的在各個算法間切換,造成很多邏輯判斷,我們可以配合使用一些其他的模式去消除。