# 单例模式

## 模式动机

在某些系统中，只有一个实例是非常必要的。比如任务管理器，首先从需求上来讲，一个任务管理器窗口完全满足需要。多个任务管理器窗口只会造成**额外的开销**，还需要处理各个窗口数据同步的问题。

## 实现

用一个变量来标记当前的类是否创建过对象，如果没创建过，返回创建之后的实例，如果之前已经创建过，**则返回之前创建过的实例**。

![单例模式「任务管理器」](/files/-Ll_kpZeicDd3-OsuSCq)

### 代码

```javascript
function TaskManage(name) {
  this.name
}

TaskManage.getInstance = (function() {
  let instance = null
  return function(name) {
    if (!instance) {
      instance = new TaskManage(name)
    }
    return instance
  }
})()

// 获取对象1

const a = TaskManage.getInstance('a')
// 获取对象2
const b = TaskManage.getInstance('b')
// 进行比较
console.info(a === b) // true
```

可以看到 `a` 和 `b` 是相等的，但是假如我们想让打开的英雄联盟也是单例，我们就必须再写一个英雄联盟的类，并添加 `getInstance` 方法，这样显然 `getInstance` 是重复编写的，我们可以将其抽出来单独作为一个类。

### 通用的单例中间类

首先我们将控制生成单例类的 `getInstance` 方法抽离出来

```javascript
// 获取单独的实例
const singleton = function(fn) {
    const instance;
    return function() {
        return instance || (instance = fn.apply(this, arguments));
    }
}

// 个人认为这样也可以
const singleton = function(Fn) {
    const instance
    return function() {
        return instance || (instance = new Fn(...arguments))
    }
}

```

我们再编写一个任务管理器的类

```javascript
const taskManage = function(name){
    this.name = name
}

taskManage.prototype.getName = function() {
    return this.name
}
```

然后我们将 `taskManage` 变为单例

```javascript
const TaskManageSingleton = singleton(taskManage)
const win = TaskManageSingleton('win')
const mac = TaskManageSingleton('mac')

console.info(win.getName()) // 'win'
console.info(mac.getName()) // 'win'
```

可以看到第二次调用 `TaskManageSingleton` 时传入的参数并未生效，可以得知返回的是之前已经生成的 `TaskManage` 实例。

## 小结

单例模式确保某一个类**只有一个实例**，而且自行实例化并向整个系统提供这个实例，这个类称为单例类，它提供全局访问的方法。单例模式的要点有三个：一是某个类只能有一个实例；二是它必须**自行创建**这个实例；三是它必须自行向整个系统提供这个实例。单例模式是一种对象创建型模式。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://haoqinn.gitbook.io/handbook-of-design-pattern/untitled.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
