理解并实现设计模式
设计模式概览
创建型模式:将创建和使用代码解耦
- 单例
- 工厂方法
- 抽象工厂
- 生成器
- 原型
结构型模式:将不同功能的代码接耦
- 装饰器
- 代理
- 适配器
- 桥接
- 组合
- 外观
- 享元
行为模式:将不同行为的代码解耦
- 迭代器
- 观察者
- 策略
- 责任链
- 命令
- 中介者
- 备忘录
- 状态
- 模板方法
- 访问者
单例模式
https://juejin.cn/post/6844903874210299912
https://juejin.cn/post/7299671045613928460?from=search-suggest
单例模式:限制类只能进行一次实例化,一个类只有一个实例,并提供一个它的全局访问点。
单例模式特点
- 全局唯一实例:单例模式确保一个单例类只有一个实例对象。
- 全局访问点:提供一个访问实例的全局入口,使得任何地方都能获取到同一个实例。
- 延迟实例化:实例对象只在第一次请求时创建,之后都返回相同的实例。
如何实现一个单例?
通过闭包实现
可以通过一个 id 生成器来理解单例模式。要保证整个应用中只有一个 id 生成器实例,并且生成的 id 互补相同且不断递增。
js
const IdGenerator = (function(){
let instance; // 保存生成的单例实例
let id = 0; // 私有变量,用于跟踪 id
// 定义构造函数,这个构造函数不会被外部访问
function createInstance(){
return{
getId: function(){
id += 1;
return id;
},
};
}
return {
getInstance: function(){
if(!instance){
instance = createInstance();// 如果实例不存在,则创建它
}
return instance;
},
};
})();
// 使用示例
const idGenerator1 = IdGenerator.getInstance();
console.log(idGenerator1.getId()); // 1
console.log(idGenerator1.getId()); // 2
const idGenerator2 = IdGenerator.getInstance();
console.log(idGenerator2.getId()); // 3
console.log(idGenerator1 === idGenerator2); // true
- 闭包:
IdGenerator
是一个==立即执行函数表达式==(IIFE),它返回一个对象,包含getInstance
方法。这个 IIFE 在执行时创建了闭包,封装了instance
和id
这两个私有变量。 - 单例逻辑:
getInstance
方法首次调用时会创建一个新的instance
(如果还未创建),并返回它。再次调用getInstance
时,由于instance
已经存在,它将直接返回现有的实例。 - ID 递增:
getId
方法属于createInstance
函数返回的对象。每次调用这个方法都会使得闭包中的id
变量递增,并返回新值。
这种闭包的方法有效地隐藏了实例的创建细节和 ID 递增的内部实现,使得外部代码无法直接修改这些私有变量,只能通过公开的方法操作。这保持了封装性和单例的控制,同时也是一种典型的 JavaScript 设计模式实现。
ES6 class 实现
js
class IDGenerator{
constructor(){
this._id = 0;
}
static getInstance(){
if(!IDGenerator.instance){
IDGenerator.instance = new IDGenerator();
}
return IDGenerator.instance;
}
getId(){
return this._id++;
}
}
const idGenerator1 = IDGenerator.getInstance();
console.log(idGenerator1.getId());
console.log(idGenerator1.getId());
const idGenerator2 = IDGenerator.getInstance();
console.log(idGenerator2.getId()); // 3
console.log(idGenerator1 === idGenerator2); // true
工厂方法模式
工厂模式能够实现的功能是:根据不同的传入参数,拿到不同的类的实例。
核心思想:将对象的创建与对象的实现分离。
构造函数模式
发布订阅模式
发布订阅模式是一种对象之间一对多的依赖关系,当一个对象的状态发生变化的时候 ,所有依赖于它的对象都将得到状态改变的通知。
实现思路:
- 订阅者把自己想订阅的事件注册到调度中心
- 当发布者发布该事件,也就是该事件被触发时,调度中心通知所有该事件的订阅者,调用它们的回调函数。
用 js 实现一个简单的发布-订阅模式:
js
class EventEmitter {
constructor() {
this._events = {}; // 调度中心
}
// 订阅者注册事件到调度中心
on(eventName, callback) {
if (!this._events[eventName]) {
this._events[eventName] = [];
}
this._events[eventName].push(callback);
}
// 取消订阅
off(eventName, callback) {
if (!this._events[eventName]) {
return;
}
this._events[eventName] = this._events[eventName].filter(cb => cb !== callback);
}
// 触发事件,调度中心通知所有*该事件*的订阅者,调用它们的回调函数
emit(eventName, ...args) {
if (!this._events[eventName]) {
return;
}
this._events[eventName].forEach(cb => {
cb(...args);
});
}
// 订阅一次性事件
once(eventName, callback) {
const onceWrapper = (...args) => {
callback(...args);
this.off(eventName, onceWrapper);
};
this.on(eventName, onceWrapper);
}
}
export { EventEmitter };