第15课:设计模式——代码的“武林秘籍”

63 阅读2分钟

别害怕前方的风浪,你比想象中更强大!

当你面对复杂代码手足无措时,是否渴望拥有“一招制敌”的绝技?设计模式就是编程世界的武功秘籍!本节课将传授 单例模式、观察者模式、工厂模式 三大绝学,用「消息通知系统」实战融会贯通,让你的代码战斗力飙升!

一、设计模式是什么?

1. 编程世界的“功夫套路”

  • 定义:针对常见问题的通用解决方案模板
  • 价值:提升代码复用性、可维护性、团队协作效率

二、三大必学模式精讲

1. 单例模式:唯一掌门人

核心思想

  • 确保一个类只有一个实例(如浏览器 window 对象)

代码实现

class Logger {
  constructor() {
    if (!Logger.instance) {
      this.logs = [];
      Logger.instance = this;
    }
    return Logger.instance;
  }

  log(message) {
    this.logs.push(message);
    console.log(`[日志] ${new Date().toISOString()}: ${message}`);
  }
}

// 测试
const logger1 = new Logger();
const logger2 = new Logger();
console.log(logger1 === logger2); // true(同一个实例)
logger1.log('用户登录');
logger2.log('数据加载');

应用场景: 全局状态管理、日志工具、数据库连接

2. 观察者模式:消息驿站

核心思想

  • 定义对象间的一对多依赖,一个对象状态改变时自动通知所有依赖者

代码实现

class NewsPublisher {
  constructor() {
    this.subscribers = [];
  }

  subscribe(fn) {
    this.subscribers.push(fn);
  }

  unsubscribe(fn) {
    this.subscribers = this.subscribers.filter(sub => sub !== fn);
  }

  notify(news) {
    this.subscribers.forEach(sub => sub(news));
  }
}

// 使用
const publisher = new NewsPublisher();

// 订阅者A
publisher.subscribe(news => {
  console.log(`[订阅者A] 收到新闻:${news}`);
});

// 订阅者B
publisher.subscribe(news => {
  document.body.innerHTML += `<p>${news}</p>`;
});

// 发布新闻
publisher.notify('JavaScript发布新特性!');

应用场景: 事件系统、实时数据推送、UI 更新

3. 工厂模式:标准化生产线

核心思想

  • 封装对象创建过程,根据输入返回不同类实例

代码实现

class Button {
  constructor(text) {
    this.text = text;
  }
  render() {
    console.log(`渲染按钮:${this.text}`);
  }
}

class IconButton extends Button {
  render() {
    console.log(`渲染图标按钮:${this.text} + 🎨`);
  }
}

class ButtonFactory {
  static create(type, text) {
    switch(type) {
      case 'primary':
        return new Button(text);
      case 'icon':
        return new IconButton(text);
      default:
        throw new Error('未知按钮类型');
    }
  }
}

// 生产按钮
const btn1 = ButtonFactory.create('primary', '提交');
const btn2 = ButtonFactory.create('icon', '收藏');
btn1.render(); // 渲染按钮:提交
btn2.render(); // 渲染图标按钮:收藏 + 🎨

应用场景: UI 组件库、复杂对象创建、多环境适配

三、实战:全局消息通知系统

1. 功能需求

  • 任意组件可发送全局通知
  • 多个地方可订阅接收通知
  • 支持一次性订阅

2. 完整代码

// 单例消息中心
class MessageCenter {
    constructor() {
        if (!MessageCenter.instance) {
            this.subscribers = new Map(); // Map保存订阅者
            MessageCenter.instance = this;
        }
        return MessageCenter.instance;
    }

    // 订阅
    on(event, callback) {
        if (!this.subscribers.has(event)) {
            this.subscribers.set(event, []);
        }
        this.subscribers.get(event).push(callback);
    }

    // 取消订阅
    off(event, callback) {
        const listeners = this.subscribers.get(event);
        if (listeners) {
            this.subscribers.set(event, listeners.filter(fn => fn !== callback));
        }
    }

    // 发布(支持传参)
    emit(event, ...args) {
        const listeners = this.subscribers.get(event);
        if (listeners) {
            listeners.forEach(fn => fn(...args));
        }
    }
}

// 创建单例
const messageBus = new MessageCenter();

// ---------- 使用示例 ----------
// 订阅登录事件
const loginHandler = user => {
    console.log(`用户登录:${user.name}`);
    document.body.innerHTML += `<div class="toast">欢迎回来,${user.name}!您的角色是 ${user.role}</div>`;
};
messageBus.on('login', loginHandler);

// 发布登录事件
messageBus.emit('login', { name: '小明', role: '超级管理员' });
messageBus.emit('login', { name: '小王', role: '浏览者' });

// 取消订阅
// messageBus.off('login', loginHandler);

下节预告

第 16 课:性能优化——让代码飞起来

  • 防抖与节流原理剖析
  • 内存泄漏排查技巧
  • 实战:优化大型数据列表渲染

回复【JS】获取本课源码+工具包!