# JavaScript设计模式

## 前言

设计模式是可重用的用于解决软件设计中一般问题的方案。设计模式如此让人着迷，以至在任何编程语言中都有对其进行的探索。

其中一个原因是它可以让我们站在巨人的肩膀上，获得前人所有的经验，保证我们以优雅的方式组织我们的代码，满足我们解决问题所需要的条件。

设计模式同样也为我们描述问题提供了通用的词汇。这比我们通过代码来向别人传达语法和语义性的描述更为方便。

本文我们将阐述JavaScript编程语言中经典和现代的设计模式。

## 反模式

如果我们认为模式代表一个最佳的实践，那么反模式将代表我们已经学到一个教训。受启发于Gof的《设计模式》，Andrew Koeing在1995年的11月的C++报告大会上首次提出反模式。在Koeing的报告中，反模式有着两种观念:

* 描述对于一个特殊的问题，提出了一个*糟糕的*解决方案，最终导致一个坏结果发生
* 描述*如何*摆脱上述解决方案并能提出一个好的解决方案

## 常用的设计模式

### 单例模式

\*\*单例模式是指能够全局访问且只能被实例化一次的类。\*\*这个单一的实例可以在我们的应用程序中共享，这使得单例模式非常适合管理应用程序中的全局状态。

实现一个单例模式的类非常简单，我们只需要用一个变量来标识这个类是否已经声明过了即可，在`constructor`中对这个标识进行判断，如果类之前已经实例化过了，则阻止该类继续实例化。

如果不想额外地声明变量，也可以直接用类的静态属性来进行标识。

```tsx
class SingleClass {
  static hasInstance = false;

  constructor() {
    if (SingleClass.hasInstance) {
      throw new Error("SingleClass已经被实例化过了");
    }
    SingleClass.hasInstance = true;
    //...
  }
}
const instance1 = new SingleClass();
const instance2 = new SingleClass();
/*
Error: SingleClass已经被实例化过了
    at new SingleClass (/project/sandbox/index.js:6:13)
    at Object.<anonymous> (/project/sandbox/index.js:13:19)
*/
```

可以更进一步，将实例通过`Object.freeze()` 进行冻结。被冻结的对象再也不能被修改；冻结了一个对象则不能向这个对象添加新的属性，不能删除已有属性，不能修改该对象已有属性的可枚举性、可配置性、可写性，以及不能修改已有属性的值。此外，冻结一个对象后该对象的原型也不能被修改。

```tsx
export default Object.freeze(new SingleClass());
```

## 参考

[Learning JavaScript Design Patterns](https://www.patterns.dev/posts/classic-design-patterns/)
