一.关于策略模式
含义
定义一系列算法,并使他们可以相互替换
这里的替换是指在Context环境类中替换所引用的策略从而实现算法的替换
目的
将算法的使用和算法的实现分离开来
基本组成
策略模式至少需要两部分
- 策略类(可变):封装了具体的算法,并负责具体的计算过程,策略类中定义了不同的策略,不同的策略对应不同的具体算法(计算方式)。
- 环境类Context(不变):接受请求,并根据调用具体的策略类中的具体策略来实现计算,实际上可以将环境类理解为一个函数,在该函数中引用了策略类对函数的参数进行计算并输出策略计算结果。
策略模式的定义看起来很笼统,在实际开发中,当需求需要进行多种条件判断(分支很多)时,传统上会使用
if-else
或者switch-case
来判断,这时候我们可以考虑策略模式来实现。
二.示例
计算水果价格
需求:根据水果的重量weight
和水果的种类fruit
计算水果价格。
-
传统实现
calculateFruitPrice(fruit,weight) { switch(fruit) { case 'apple': return 4 * weight case 'banana': return 3 * weight case 'orange': return 5 * weight } }
这里我们使用了switch语句对不同的水果种类进行计算价格,可以看到计算水果价格的具体实现和使用都是通过
calculateFruitPrice
来完成。当我们计算某种水果价格的时候,需要关注calculateFruitPrice
方法中是否包含了该种类水果,以及新增某种水果时要在calculateFruitPrice
方法中增加分支。 -
使用策略模式
按照策略模式的基本组成,我们将
calculateFruitPrice
进行分离,首先定义一个strategy
,用来计算不同水果的价格,然后在calculateFruitPrice
方法中实现对策略的引用从而计算出水果的价格,这里我们可以看到在calculateFruitPrice
方法中,我们没有对水果价格计算的具体实现,在计算水果价格的时候,也不需要关心该种水果价格计算方式是否已经定义了,这是strategy
所关心的事。// 定义策略(算法具体实现) const strategy = { apple: weight => weight * 4, babana: weight => weight * 3, orange: weight => weight * 5, } // 定义算法使用 const calculateFruitPrice = (fruit, weight) => strategy[fruit](weight) const log = console.log log(calculateFruitPrice('apple', 5)) // 20 log(calculateFruitPrice('babana', 2)) // 6 log(calculateFruitPrice('orange', 3)) // 15
可以看到在使用策略模式时我们定义的策略是基于分支定义的,比如基于水果的种类而定义了一系列的算法来实现了对不同种类水果价格的计算。
表单校验
三.策略模式的优缺点
优点
- 避免过多的条件分支,使代码简洁,便于维护
- 易于拓展,只需要增加策略或修改策略,调用方式不会变动
缺点
过多的使用策略模式,会在程序中创建或者暴露出过多的策略类对象。