Skip to content

理解并实现设计模式

设计模式概览

设计模式目录

创建型模式:将创建和使用代码解耦

  • 单例
  • 工厂方法
  • 抽象工厂
  • 生成器
  • 原型

结构型模式:将不同功能的代码接耦

  • 装饰器
  • 代理
  • 适配器
  • 桥接
  • 组合
  • 外观
  • 享元

行为模式:将不同行为的代码解耦

  • 迭代器
  • 观察者
  • 策略
  • 责任链
  • 命令
  • 中介者
  • 备忘录
  • 状态
  • 模板方法
  • 访问者

单例模式

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
  1. 闭包: IdGenerator 是一个==立即执行函数表达式==(IIFE),它返回一个对象,包含 getInstance 方法。这个 IIFE 在执行时创建了闭包,封装了 instanceid 这两个私有变量。
  2. 单例逻辑: getInstance 方法首次调用时会创建一个新的 instance(如果还未创建),并返回它。再次调用 getInstance 时,由于 instance 已经存在,它将直接返回现有的实例。
  3. 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

工厂方法模式

medium 工厂方法讲解

工厂模式能够实现的功能是:根据不同的传入参数,拿到不同的类的实例。

核心思想:将对象的创建与对象的实现分离。

构造函数模式

发布订阅模式

发布订阅模式是一种对象之间一对多的依赖关系,当一个对象的状态发生变化的时候 ,所有依赖于它的对象都将得到状态改变的通知。

实现思路:

  1. 订阅者把自己想订阅的事件注册到调度中心
  2. 当发布者发布该事件,也就是该事件被触发时,调度中心通知所有该事件的订阅者,调用它们的回调函数。

用 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 };

观察者模式

策略模式

装饰器模式