JavaScript设计模式笔记(二)策略模式

什么是策略模式

策略模式的定义为:

定义一系列的算法,把它们一个个封装起来,并且使它们可以相互替换
—-《JavaScript设计模式与开发实践》

即是说,当一个对象要完成某件事,该对象有多个完成该事的方法,我们把这些方法都封装起来,该对象知道的只有在哪个情况下要使用其中的哪个方法,而并不知道该方法的具体实现。

在策略模式中,我们需要有一方明确怎么实现各种方法,还要有一方判断要调用哪一个方法,我们将前者称作策略方,将后者称为调用方,假如现在我们有这样的需求,要给一个公司里面的员工发工资,员工分为a,b,c三个等级,每个等级的员工的工资不一样,现在我们要查询某个员工的工资。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
let strategies = { // 策略方
a: () => {
return 10000
},
b: () => {
return 8000
},
c: () => {
return 5000
}
}

var calculateSalary = (name, rank) => { // 调用方
console.log(`${name}的工资是${strategies[rank]()}`)
}

calculateSalary('jack', 'a') // jack的工资是10000
calculateSalary('Mary', 'b') // Mary的工资是8000

策略方定下三种查工资的方式,然后在调用方调用其中的某一种方式,这就是策略模式。

策略模式的优点

  1. 减少了许多条件选择语句,直接使用属性来选择其中一种方式,这样的方式看起来也更加直观

  2. 将策略方/方法的实现和调用方/调用方法的选择很好地分开,当我们要修改其中一种方式时,只需修改策略方上的方法即可,调用方不用做任何修改,扩展方面也很方便,假如上面的需求中,突然多了一个职位“s”,工资不同于上面几种,这个时候我们只要在策略方中添加一个方法即可

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    let strategies = { // 策略方
    a: () => {
    return 10000
    },
    b: () => {
    return 8000
    },
    c: () => {
    return 5000
    },
    s: () => {
    return 12000
    }
    }
  3. 策略方的方法可以在多个地方重复调用,减少了代码多次重复的复制粘贴

策略模式的缺点

  1. 污染命名空间

如上的代码中在全局中定义了一个全局的对象用于表示策略方,这样的做法会使得该名字占用了一个变量名,如果在后面某个部分不小心使用了该变量名,那毫无疑问会引起许多报错

  1. 增加在作用域中的类或对象

使用策略模式,我们要完成一个事情,必须至少增添一个类或对象,这样可能会在代码中创建过多的类,我们可以通过在全局中将所要用到的类/对象作为属性放在一个对象中,这样会尽可能地减少对象的创建

  1. 违反最少知识原则

虽然计算方面的内容会由策略方来完成,但是选择的任务还是落在调用方上,因此调用方必须对策略方的方法有一定的了解,而这个是违反了最少知识原则


参考自曾探的《JavaScript设计模式与开发实践》