什么是策略模式
策略模式的定义:定义一系列的算法,将它们一个个封装起来,并且它们之间可以相互替换。
例如,春节的时候,大部分的人都会选择回老家过年,那么可以根据实际情况选择不同的出行方式
- 有钱没时间的,可以选择飞机
- 没钱有时间的,可以选择火车
- 一点钱都没有的,走回去🐶
另一个例子,在日常压缩文件的时候,既可以选择zip算法,也可以选择7z算法。这些算法灵活多样可以互相替换。
策略模式的核心是将实现和调用分离,它通常包含两个组成部分:策略类
和 环境类
。策略类用来封装具体的算法,负责具体的计算过程。环境类用来接收客户的请求,并把请求委托给某个策略类执行。
以计算算年终奖为例:
很多公司的年终奖是根据员工的工资基数和年底绩效情况来发放的。例如,绩效为S的人年终奖有4倍工资,绩效为A的人年终奖有3倍工资,而绩效为B的人年终奖是2倍工资。假设财务部要求我们提供一段代码,来方便他们计算员工的年终奖。
- 最初始的实现
const calculateBonus = function(level, salary){
if(level === 'S') {
return salary * 4
}
if(level === 'A') {
return salary * 3
}
if(level === 'B') {
return salary * 2
}
}
calculateBonus('S',40000) // 80000
上面这种实现方式的缺点:
- 函数庞大,大量的if-else条件语句,需要覆盖所有场景
- 如果需要新增绩效级别C或者更改绩效S奖金系数5,需要深入到函数内部调整,这不符合开发-闭合原则
- 复用性差,如果需要在别的地方复用这些规则,只能进行粘贴、复制
以下是基于传统面向对象语言,通过策略模式来实现
// 定义策略类
const performanceS = function(){}
performanceS.prototype.calculate = function(salary){
return salary * 4
}
const performanceA = function(){}
performanceS.prototype.calculate = function(salary){
return salary * 3
}
const performanceB = function(){}
performanceS.prototype.calculate = function(salary){
return salary * 2
}
// 定义环境类
const Bounds = function(level, salary){
this.salary =null
this.strategy = null
}
Bounds.prototype.setSalary = function(salary){
this.salary = salary
}
Bounds.prototype.strategy = function(strategy){
this.strategy = strategy
}
Bounds.prototype.getBounds = function(){
return this.strategy.calculate(this.salary)
}
const bounds = new Bounds()
bounds.setSalary(40000)
bounds.strategy(new performanceA())
bounds.getBounds() // 80000
上面的代码中各个类的职责更加鲜明、清晰,但是这只是基于传统面向对象语言的模仿,下面基于 javascript 实现策略模式。
上面中 strategy 对象是通过策略类创建来的,但是在Javascript 中函数也是对象,所以更简单直接的做法是把 strategy 直接定义为函数
const strategy = {
'S': function(salary){
return salary*4
},
'A': function(salary){
return salary*3
},
'B': function(salary){
return salary*2
},
}
const calculateBonus = function(level, salary){
return strategy[level](salary)
}
console.log(calculateBonus('S',40000) // 80000
另一种通过高阶函数的实现方式。在Javascript 中,策略类常常被函数所代替,这策略模式就成了一种“隐形”模式。
const S = function(salary){
return salary*4
}
const A = function(salary){
return salary*3
}
const B = function(salary){
return salary*2
}
const calculateBonus = function(salary,func){
return func(salary)
}
console.log(calculateBonus('S',40000) // 80000