# 模拟场景

开完会后,经理给你分配了一个任务,让你给管理系统开发一个针对不同的用户设置不同的权限的功能。假设目前的角色有管理员、前端开发人员、后端开发人员。

你可能会写出下面这样的代码:

function setPermissions(role) {
  if (role === 'admin') {
    // ...
  }else if (role === 'back') {
    // ...
  }else if (role === 'front') {
    // ...
  }
}

虽然猛一看好像没什么问题,功能也能正常运行,但它首先违背了设计模式里的 ”单一职责“ 原则。上述代码将不同角色的权限内容都设置在了一个函数中,导致设置权限的函数变的十分臃肿,修改的话也不好修改,可谓牵一发而动全身,下面我们针对 “单一职责” 原则对代码进行优化。

function adminPermissions() {
  // ...
}
function backPermissions(){
  // ...
}
function frontPermissions() {
  // ...
}

function setPermissions() {
  if (role === 'admin') {
    adminPermissions()
  }else if (role === 'back') {
    backPermissions()
  }else if (role === 'front') {
    frontPermissions()
  }
}

上面我们将不同用户的权限封装到了不同的函数中,如果某个用户的权限内容发生了变化,只需要修改对应的函数即可。

其次它还违反了 ”开放封闭“ 原则。假设现在又新增了测试人员,你该怎么办呢?你可能会想,那有什么呢?直接在在下面增加一个判断酒店就好了呀,你可能会写出下面这样的代码:

function setPermission(role) {
  if (role === 'admin') {
    // ...
  }else if (role === 'back') {
    // ...
  }else if (role === 'front') {
    // ...
  }else if (role === 'tester') {
    // ...
  }
}

上面我们给测试人员增加了权限操作,但是是通过直接修改 setpermission 方法实现的。可以看出它违反了 ”开放封闭“(对扩展开放,对修改封闭)原则。

下面我们来针对 ”开放封闭“ 原则对代码进行优化。

我们先来看一下最开始的代码主要是实现的什么功能?我们通过 if...else if... 来判断不同的角色,并给予不同的权限,好像是一个映射关系。在 JS 中有没有现成的映射关系数据结构呢?答案是有的,就比如对象。我们可以使用对象来优化上面的代码。

const permissions = {
  admin(){
    // ...
  },
  back(){
    // ...
  },
  front(){
    // ...
  },
  tester(){
    // ...
  }
}

function setPermissions(role) {
  return permissions[role]()
}

上面我们就针对 “开放封闭” 原则对代码进行了优化。通过上面的优化,我们可以看到设置权限的函数里面只有一行代码,职责非常单一。当需要给新的用户设置权限的时候,我们只需要扩展permissions这个对象即可。比如,我们需要给运营同学添加权限:

permissions.operations = function() {
  // ...
}

# 策略模式

上面的重构过程就是对策略模式的一种应用。下面我们来看一下策略模式的定义:

策略模式

定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。

从上面的例子我们可以看出,设置权限的逻辑对应的就是定义里的 “算法” ,对各个用户的权限进行抽离对应的就是定义里的 “封装” ,使用对象进行映射,对应了定义里的 “替换” 。