JavaScript设计模式:策略模式
Posted leayun
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JavaScript设计模式:策略模式相关的知识,希望对你有一定的参考价值。
定义
策略模式定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的变化不会影响使用算法的客户。策略模式属于对象行为模式,它通过对算法进行封装,把使用算法的责任和算法的实现分割开来,并委派给不同的对象对这些算法进行管理。
简而言之,就是策略模式准备了一组算法,并将每个算法进行封装,使它们之间可用相互替换。 策略模式除了用来封装算法,也可以用来封装一系列的"业务规则",只要这些业务规则指向的目标一致,并且可以被替换使用,我们就可以用策略模式来封装它们。
例子:购物车结算时有多种折扣计算方式,满100-10,满200-25,8折,7折,这种逻辑我们可以用基本代码实现
function calcPrice(price, type) {
if (type === \'100-10\') {
price -= 10
} else if (type === \'200-25\') {
price -= 25
} else if (type === \'80%\') {
price *= 0.8
}
return price
}
const res = calcPrice(320, \'100-10\')
显而易见,这段代码虽然实现了我们想要的功能,但是很局限,有以下几种缺点:
- 一旦折扣种类修改,需要反复改源代码,违反了开放封闭原则
- 很容易陷入多重条件地狱,不断去累加判断条件
- 算法无复用性,在程序的其他地方需要重用,只能复制粘贴
相关概念
一个基于策略模式的程序至少由两部分组成。第一个部分是一组策略类,第二个部分是环境类Context。- 策略类:策略类封装了具体的算法,并负责具体的计算过程。
- 环境类Context:环境类Context接受客户的请求,随后把请求委托给某一个策略类。
const calcPrice = (function () {
const sale = {
\'100-10\': function (price) { return price -= 10 },
\'200-25\': function (price) { return price -= 25 },
\'80%\': function (price) { return price *= 0.8 }
}
return function(price,type) {
// 判断对象里有没有这个折扣类型
if (!sale[type]) return \'没有这个折扣\'
return sale[type](price)
}
})()
console.log(calcPrice(320,\'100-10\'))
// 替换 Context 中当前保存的策略对象,便能执行不同的算法来得到我们想要的结果。
// 增加添加和删除折扣的接口
const calcPrice = (function () {
const sale = {
\'100-10\': function (price) {return price -= 10},
\'200-25\': function (price) {return price -= 25},
\'80%\': function (price) {return price *= 0.8}
}
function calcPrice(price, type) {
if (!sale[type]) return \'没有这个折扣\'
return saletype
}
calcPrice.add = function (type, fn) {
// 判断折扣是否存在
if (sale[type])
sale[type] = fn
return \'添加成功\'
}
// 删除折扣
calcPrice.del = function (type) {
delete sale[type]
}
return calcPrice
})()
// 添加折扣
calcPrice.add(\'70%\', function (price) {return price *= 0.7})
// console.log(calcPrice(300,\'70%\'))
// 删除折扣
calcPrice.del(\'100-10\')
// console.log(calcPrice(300,\'100-10\'))
策略模式的优缺点
从上述的例子中,很明显能总结出策略模式的优点
- 采用组合、委托和多态等技术和思想、有效避免了多重条件选择语句
- 采用了开放-封闭原则,将算法封装在独立的strategy中,易于理解、切换、拓展
- 策略模式中的算法可以进行复用,从而避免很多地方的复制粘贴
同时策略模式也有其缺点,但是并不影响我们对策略模式的使用
- 在策略模式中,我们会增加很多策略类、策略对象
- 要使用策略模式,我们必须了解到所有的strategy、必须了解各个strategy之间的不同点,才能选择一个适合的strategy。
JavaScript设计模式中策略模式的使用方法
策略模式
策略模式
定义一系列的算法,把它们一个个封装起来,并且使它们可以互相替换
简单来说是:定义一系列的算法,把它们各自封装成策略类,算法被封装在策略类内部的方法里,在客户对 Context 发起请求的时候,Context 总是把请求委托给这些策略对象中间的某一个进行计算。目的将算法的使用与算法的实现分离开来
策略模式组成组成
- 策略类:封装具体的算法,并负责具体的计算过程
- 环境类 Context,Context 接受客户的请求,随后把请求委托给某一个策略类。要做到这一点 Context 要维持对某个策略对象的引用。
多态在策略模式中的体现
每个策略对象负责的算法已被各自封装在对象内部,当我们发起计算奖金时,它们会返回不同的计算结果,这正是对象多态性的体现。替换 Context 中当前保存的策略对象,便能执行不同的算法得到我们想要的结果。
多态
- 同一操作作用于不同的对象上面,可以产生不同的解释和不同的执行结果。换句话说,给不同的对象发送同一个消息的时候,这些对象会根据这个消息分别给出不同的反馈。
- 多态思想:将“做什么”和“谁去做以及怎样去做”分离开来,也就是将“不变的事情”与“可能改变的事物”分离开来。把不变的部分隔离出来,把可变的部分封装起来,这样就给予了我们扩展程序的能力,程序看起来是可生长的,也是符合开放-封闭原则的。
- 根本作用:通过把过程化的条件分支语句转化为对象的多态性,从而消除这些条件分支语句。
策略模式的优点
-
利用组合、委托、多态等技术和思想,减少多重条件语句
-
符合开放封闭原则,把算法封装在独立的对象中,使得对象易于切换、易于理解、易于扩展
-
代码逻辑可复用,减少重复工作
-
将行为分布在各个对象中,并让这些对象各自负责自己的行为,这正是面向对象设计的优点。
-
例子: 计算绩效奖金
-
const calculateBonus = function (level, salary)
if (level == "S")
return salary _ 4;
else if (level == "A")
return salary _ 3;
else if (level == "B")
return salary \\* 2;
else
return salary;
;
console.log(calculateBonus("S", 10000));
- 缺点:
- 后期随着绩效种类的增加,calculateBonus 函数可能会越来越庞大
- 实现起来简单方便,但是 if-else 很多,这些语句需要覆盖所有的逻辑分支
- 函数缺乏弹性,修改必须深入函数内部逻辑才可以进行修改,不符合开放-封闭原则
改造方案一
- 使用组合函数重构代码
- 我们把各种算法封装到一个个的小函数里面。
const performanceS = function (salary)
return salary _ 4;
;
const performanceA = function (salary)
return salary _ 3;
;
const performanceB = function (salary)
return salary \\* 2;
;
const calulateBonus2 = function (level, salary)
if (level === "S")
return performanceS(salary);
else if (level === "A")
return performanceA(salary);
else if (level === "B")
return performanceB(salary);
else
return salary;
;
console.log(calulateBonus2("S", 10000));
- 没有解决最重要的问题:后期随着绩效种类的增加,calculateBonus 函数可能会越来越庞大
改造方法二
面向对象的策略模式
const PS = function () ;
PS.prototype.calculate = function (salary)
return salary _ 4;
;
const PA = function () ;
PA.prototype.calculate = function (salary)
return salary _ 3;
;
const PB = function () ;
PB.prototype.calculate = function (salary)
return salary \\* 2;
;
const Bons4 = function ()
this.salary = null;
this.strategy = null; // 绩效等级对应的策略对象,
;
Bons4.prototype.setSalary = function (salary)
this.salary = salary; // 设置原始工资
;
Bons4.prototype.setStrategy = function (strategy)
this.strategy = strategy; // 设置绩效等级对应的策略对象,
;
Bons4.prototype.getBons4 = function ()
return this.strategy.calculate(this.salary); // 设置绩效等级对应的策略对象,
;
const bonus4 = new Bons4();
bonus4.setSalary(10000);
bonus4.setStrategy(new PS());
console.log(bonus4.getBons4());
Javascript 计算奖金版本的策略模式,
在 JavaScrpt 中,函数也是对象,简单直接的做法是把 strategy 直接定义为函数
const strategire =
S: function (salary)
return salary _ 4;
,
A: function (salary)
return salary _ 3;
,
B: function (salary)
return salary \\* 2;
,
;
// 2. Context 接受用户的请求
const calulateBonus3 = function (level, salary)
return strategire[level](salary);
;
console.log(calulateBonus3("S", 10000));
以上是关于JavaScript设计模式:策略模式的主要内容,如果未能解决你的问题,请参考以下文章