# Strategy（策略模式）

Strategy（策略模式）属于行为型模式。

**意图：定义一系列的算法，把它们一个个封装起来，并且使它们可以相互替换。本模式使得算法可以独立于使用它的客户而变化。**

策略是个形象的表述，所谓策略就是方案，我们都知道任何事情都有多种方案，而且不同方案都能解决问题，所以这些方案可以相互替换。我们将方案从问题中抽象出来，这样就可以抛开问题，单独优化方案了，这就是策略模式的核心思想。

## 举例子

如果看不懂上面的意图介绍，没有关系，设计模式需要在日常工作里用起来，结合例子可以加深你的理解，下面我准备了三个例子，让你体会什么场景下会用到这种设计模式。

### 地图导航

我们去任何地方都可以选择步行、骑车、开车、公交，不同的方案都可以帮助我们到达目的地，那么很明显应该将这些方案变成策略封装起来，接收的都是出发点和目的地，输出的都是路线。

### 布局方式

比如我们做一个报表系统，在 PC 使用珊格布局，在移动端使用流式布局，其实内容还是那些，只是布局方式会随着不同终端大小做不同的适配，那么布局的适配就是一种策略，它可以与报表内容无关。

我们可以将布局策略单独抽取出来，以后甚至可以适配电视机、投影仪等等不同尺寸的场景，而不需要对其他代码做任何改动，这就是将布局策略从代码中解耦出来的好处。

### 排序算法

当我们调用 `.sort` 时，使用的是什么排序算法？可能是冒泡、快速、插入排序？其实无论何种排序算法，本质上做的事情都是一样的，我们可以事先将排序算法封装起来，针对不同特性的数组调用不同的排序算法。

## 意图解释

**意图：定义一系列的算法，把它们一个个封装起来，并且使它们可以相互替换。本模式使得算法可以独立于使用它的客户而变化。**

算法可以理解为策略，我们制定许多解决某个场景的策略，这些策略都可以独立的解决这个场景的问题，这样下次遇到这个场景时，我们就可以选择任何策略来解决，而且我们还可以脱离场景，单独优化策略，只要接口不变即可。

这个意图本质上就是解耦，解耦之后才可以分工。想想一个复杂的系统，如果所有策略都耦合在业务逻辑里，那么只有懂业务的人才能小心翼翼的维护，但如果将策略与业务解耦，我们就可以独立维护这些策略，为业务带来更灵活的变化。

## 结构图

<img width=600 src="https://img.alicdn.com/imgextra/i1/O1CN01oQ1Vvc1kHPXNk8vzD_!!6000000004658-2-tps-1578-480.png">

- Strategy: 策略公共接口。
- ConcreteStrategy: 具体策略，实现了上面这个接口。

只要你的策略符合接口，就满足策略模式的条件。

## 代码例子

下面例子使用 typescript 编写。

```typescript
interface Strategy {
  doSomething: () => void
}

class Strategy1 implements Strategy {
  doSomething: () => {
    console.log('实现方案1')
  }
}

class Strategy2 implements Strategy {
  doSomething: () => {
    console.log('实现方案2')
  }
}

// 使用
new System(new Strategy1()) // 策略1实现的系统
new System(new Strategy2()) // 策略2实现的系统
```

## 弊端

不要走极端，不要每个分支走一个策略模式，这样会导致策略类过多。当分支逻辑简单清晰好维护时，不需要使用策略模式抽象。

## 总结

策略模式是很重要的抽象思维，我们首先要意识到问题有许多种解法，才能意识到策略模式的存在。当一个问题需要采取不同策略，且策略相对较复杂，且未来可能要拓展新策略时，可以考虑使用策略模式。

> 讨论地址是：[精读《设计模式 - Strategy 策略模式》· Issue #304 · dt-fe/weekly](https://github.com/dt-fe/weekly/issues/304)

**如果你想参与讨论，请 [点击这里](https://github.com/dt-fe/weekly)，每周都有新的主题，周末或周一发布。前端精读 - 帮你筛选靠谱的内容。**

> 关注 **前端精读微信公众号**

<img width=200 src="https://img.alicdn.com/tfs/TB165W0MCzqK1RjSZFLXXcn2XXa-258-258.jpg">

> 版权声明：自由转载-非商用-非衍生-保持署名（[创意共享 3.0 许可证](https://creativecommons.org/licenses/by-nc-nd/3.0/deed.zh)）
