JavaScript设计模式之“策略模式”(一)

定义:定义一些列的算法,把他们一个个封装起来,并使它们可以互相替换

引用书中写的很好的一段话来诠释策略模式吧,“俗话说条条大路通罗马,现实中也有很多种不同的途径到达同一个目的地,比如我们要去旅游,如果我们时间很赶,但是不考虑钱的问题,我们可能选择坐飞机,如果我们没有什么钱,那么我们可以坐大巴或者火车,如果再穷一点,可以选择骑行”。这段话就很好的诠释了什么是策略模式,就是对于一个问题,我们可以提供多种手段去解决,而且最终的结果都是期望的结果。

下面我们拿员工奖金计算算法为例

问题是这样的,员工到了年终都会进行绩效评级,最终根据所评的等级和自身薪资情况决定年终奖的多少,绩效评级分别有:S级,A级,B级,其中S级是拿基础薪资的4倍,A级是拿基础薪资的3倍,B级是拿基础薪资的2倍,根据以上情况,设计一个计算员工年终奖的算法模块

“最笨的方法”

function getBouns(performanceLevel, salary) {
    if (performanceLevel === "S") {
        return salary * 4
    }
    if (performanceLevel === "A") {
        return salary * 3
    }
    if (performanceLevel === "B") {
        return salary * 2
    }
}

console.log(getBouns("A", 20000))
console.log(getBouns("S", 6000))

不难发现,代码十分简单,问题也十分暴露,getBouns函数十分庞大,存在了很多if-else的分支,且getBouns函数缺乏弹性,如果增加一个新的绩效等级,或者需要将S级的年终奖改为5倍基础薪资,那么就不得不去getBouns内部去修改源码而且算法复用性极差 。

使用组合函数重构代码

let performanceS = function (salary) {
    return salary * 4
}
let performanceA = function (salary) {
    return salary * 3
}
let performanceB = function (salary) {
    return salary * 2
}

function getBouns(performanceLevel, salary) {
    if (performanceLevel === "S") {
        return performanceS(salary)
    }
    if (performanceLevel === "A") {
        return performanceA(salary)
    }
    if (performanceLevel === "B") {
        return performanceB(salary)
    }
}

console.log(getBouns("S" , 5000))
console.log(getBouns("B" , 2000))

相信大家看到这段代码会嗤之以鼻一下吧,这....也算改进?哈哈,我一开始看到这个重构代码也是很疑惑,但是确实有所提高,起码抽离出了计算逻辑,减少了getBouns的赘余,不过也就仅此而已

使用策略模式重构代码

在这个例子中,算法的使用方式是不变的,都是根据某个算法取得计算后的奖金数额,而算法的实现是变化各异的,每种绩效都对应着不同的算法规则。

一个基于策略模式的程序至少由两个部分组成,第一部分是一组策略类,策略类封装了具体的算法,并负责计算过程,第二部分则是环境类,环境类接受客户的请求后,将请求交付给策略类,执行对应的算法规则,在一下重构的过程中,我们同上篇“单例模式”文章一样,先模拟传统面向对象语言的写法,之后再实现JavaScript的版本

// 定义一组策略类
const performanceS = function () { }
performanceS.prototype.calculate = function (salary) {
    return salary * 4
}
const performanceA = function () { }
performanceA.prototype.calculate = function (salary) {
    return salary * 3
}
const performanceB = function () { }
performanceB.prototype.calculate = function (salary) {
    return salary * 2
}

// 定义奖金类(环境类,此时的业务环境为计算奖金)
const Bonus = function () {
    this.salary = null     // 原始工资
    this.strategy = null   // 绩效等级对应的策略对象
}
Bonus.prototype.setSalary = function (salary) {
    this.salary = salary
}
Bonus.prototype.setStrategy = function (strategy) {
    this.strategy = strategy
}
Bonus.prototype.getBonus = function () {
    if (!this.strategy) {
        throw new Error("未设置响应的strategy属性")
    }
    return this.strategy.calculate(this.salary)
}

const bonus = new Bonus()

bonus.setSalary(10000)
bonus.setStrategy(new performanceS())
console.log(bonus.getBonus())
bonus.setSalary(2000)
bonus.setStrategy(new performanceA())
console.log(bonus.getBonus())

在实现JavaScript版本之前,仔细理解这段代码,很容易观察到,在传统面向对象语言中,为什么不将这些个策略类封装成一个对象呢,因为传统面向对象语言创建较为繁琐,还需要先创建一个构造类再来创建对象封装策略类,那么熟悉JavaScript的小伙伴就清楚了,在JavaScript中我们直接很容易的就能创建一个空对象,然后用键值对封装每个每个策略类,所以,我们直接上代码,看起来比传统代码清晰多了

let performanceObj = {
    "S": function (salary) {
        return salary * 4
    },
    "A": function (salary) {
        return salary * 3
    },
    "B": function (salary) {
        return salary * 2
    }
}

function getBonus(performanceLevel, salary) {
    return performanceObj[performanceLevel](salary)
}

 

结果毋庸置疑的是正确的的,扯句题外话,其实这两种实现方式在逻辑上是没什么太大区别的,主要是因为语言的差异性(这里就再解释一遍,上面的实现方式也是js,因为虽然是js实现,但是模拟的是传统面向对象语言的设计过程),那么那种方式实现更好呢,就这个例子而言,看上去可能JavaScript的设计更好点,但是换个场景可能就不是JavaScript更好了,每种语言都有自己的优缺点,比如传统的面向对象语言的代码维护性就比JavaScript这种的脚本语言搞很多,这也就是为什么会出现JavaScript超集Typescript这门语言了,就是为了弥补JavaScript在数据维护上的缺陷,所以大家不必要为此纠结

由于篇幅过长我将该模式分作两部分来讲,该部分先讲清楚了策略模式是什么,策略模式中包含那两部分,以及怎么通过策略模式改造代码,最后通过策略模式实现了一个基本的较为简单的案例的,下篇文中我会重点围绕表单提交案例以及多个策略作用在同一实例上的问题来继续深入探讨策略模式,注意更新噢

内容摘自《JavaScript设计模式与开发实践》· 曾探 · 著

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
JavaScript 设计模式是在 JavaScript 编程中经常使用的一种代码组织和架构方法。设计模式可以帮助开发者解决常见的问题,并提供可复用的解决方案。 以下是一些常见的 JavaScript 设计模式: 1. 工厂模式(Factory Pattern):通过使用工厂方法创建对象,将对象的创建和使用分离开来,提高代码的可扩展性和可维护性。 2. 单例模式(Singleton Pattern):确保一个类只有一个实例,并提供一个全局访问点来访问该实例。 3. 观察者模式(Observer Pattern):定义了对象之间的一对多依赖关系,当一个对象的状态发生改变时,所有依赖它的对象都会被自动通知并更新。 4. 发布-订阅模式(Publish-Subscribe Pattern):也是一种观察者模式的变体,在这种模式中,发布者(Publisher)和订阅者(Subscriber)之间通过消息队列进行通信。 5. 原型模式(Prototype Pattern):通过复制现有对象来创建新对象,避免了使用类进行实例化的复杂性。 6. 适配器模式(Adapter Pattern):将一个类的接口转换成客户端所期望的另一个接口,使得原本不兼容的类可以一起工作。 7. 装饰者模式(Decorator Pattern):动态地给对象添加新的功能,而不影响其他对象。 8. 策略模式(Strategy Pattern):定义一系列算法,将每个算法封装起来,并使它们可以互换使用。 这些设计模式可以帮助开发者在编写 JavaScript 代码时更好地组织和设计代码结构,提高代码的可读性、可维护性和可扩展性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

青灯夜游/

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值