JS常用设计模式汇总

1、基于类的单例模式

javascript 复制代码
// PageManager.js
class PageManager {
  constructor(config) {
    if (!PageManager.instance) {
      this.config = config;
      this.initialized = false;
      PageManager.instance = this;
      
      this.init();
    }
    return PageManager.instance;
  }

  init() {
    if (this.initialized) return;
    
    console.log('Initializing with config:', this.config);
    // 实际初始化逻辑
    this.initialized = true;
  }

  generatePage(instruction) {
    if (!this.initialized) {
      throw new Error('PageManager not initialized');
    }
    
    const page = {
      ...this.config,
      ...instruction,
      id: Date.now()
    };
    
    console.log('Generated page:', page);
    return page;
  }

  // 更新配置(新增方法)
  updateConfig(newConfig) {
    Object.assign(this.config, newConfig);
  }

  // 获取实例的静态方法(推荐方式)
  static getInstance(config) {
    if (!PageManager.instance) {
      PageManager.instance = new PageManager(config);
    }
    return PageManager.instance;
  }
}

// 不立即初始化,而是导出类
export default PageManager;

使用方式

javascript 复制代码
// 使用方可以决定何时初始化
import PageManager from './PageManager';

// 第一次获取实例时初始化(推荐方式)
const pageManager = PageManager.getInstance({
  defaultTemplate: 'advanced',
  baseStyles: true
});

// 生成页面
const homePage = pageManager.generatePage({ 
  title: 'Home', 
  content: 'Welcome' 
});

// 后续获取仍然是同一个实例
const sameManager = PageManager.getInstance();
console.log(pageManager === sameManager); // true

// 可以更新配置
pageManager.updateConfig({
  defaultTemplate: 'custom'
});

2、更优雅的变体:模块模式单例

如果你更喜欢模块模式而不是类,这里有一个更符合JavaScript习惯的实现:

javascript 复制代码
// pageManager.js
let instance = null;
let config = {};
let initialized = false;

const init = (initialConfig) => {
  if (initialized) {
    console.warn('PageManager already initialized');
    return;
  }
  
  config = {
    defaultTemplate: 'standard',
    ...initialConfig
  };
  
  initialized = true;
  console.log('PageManager initialized with config:', config);
};

const generatePage = (instruction) => {
  if (!initialized) throw new Error('PageManager not initialized');
  
  return {
    ...config,
    ...instruction,
    id: `page-${Date.now()}`
  };
};

const updateConfig = (newConfig) => {
  Object.assign(config, newConfig);
};

// 导出单例对象
export default {
  init,
  generatePage,
  updateConfig
};

使用方式:

javascript 复制代码
import pageManager from './pageManager';

// 在使用前初始化
pageManager.init({
  defaultTemplate: 'custom'
});

// 使用单例
const page = pageManager.generatePage({ title: 'About' });

3、使用工厂函数(更灵活)

js 复制代码
// 使用示例
// createPageGenerator.js
export const createPageGenerator = (initialConfig) => {
  const config = {
    defaultTemplate: 'standard',
    basePath: '/',
    ...initialConfig
  };
  
  const generate = (instruction) => {
    const pageId = `${config.basePath}${instruction.slug || `page-${Date.now()}`}`;
    
    return {
      ...config,
      ...instruction,
      id: pageId,
      fullPath: `${config.basePath}${instruction.path || ''}`,
      createdAt: new Date()
    };
  };
  
  const updateConfig = (newConfig) => {
    Object.assign(config, newConfig);
  };
  
  return {
    generate,
    updateConfig,
    getConfig: () => ({ ...config })
  };
};

// 使用示例
// 可以创建多个实例或单个实例使用

基本使用

js 复制代码
// 使用示例
import { createPageGenerator } from './createPageGenerator';

// 1. 创建实例(简单配置)
const simpleGenerator = createPageGenerator();
const page1 = simpleGenerator.generate({ title: 'Home' });
console.log(page1);

4、发布-订阅模式 (Pub-Sub Pattern)

用途:观察者模式的变体,使用主题/通道概念解耦发布者和订阅者。

js 复制代码
class EventBus {
  constructor() {
    this.events = {};
  }

  subscribe(eventName, callback) {
    if (!this.events[eventName]) {
      this.events[eventName] = [];
    }
    this.events[eventName].push(callback);
  }

  publish(eventName, data) {
    if (this.events[eventName]) {
      this.events[eventName].forEach(callback => callback(data));
    }
  }

  unsubscribe(eventName, callback) {
    if (this.events[eventName]) {
      this.events[eventName] = this.events[eventName].filter(
        cb => cb !== callback
      );
    }
  }
}

// 使用
const bus = new EventBus();

// 订阅
const logData = data => console.log('Received:', data);
bus.subscribe('dataUpdate', logData);

// 发布
bus.publish('dataUpdate', { newData: 123 });

// 取消订阅
bus.unsubscribe('dataUpdate', logData);

// 实际应用:Vue的EventBus、组件间通信

5、观察者模式 (Observer Pattern)

js 复制代码
// 主题(被观察者)
class Subject {
  constructor() {
    this.observers = [];
  }

  subscribe(observer) {
    this.observers.push(observer);
  }

  unsubscribe(observer) {
    this.observers = this.observers.filter(obs => obs !== observer);
  }

  notify(data) {
    this.observers.forEach(observer => observer.update(data));
  }
}

// 观察者
class Observer {
  update(data) {
    console.log('Observer received:', data);
  }
}

// 使用
const subject = new Subject();
const observer1 = new Observer();
const observer2 = new Observer();

subject.subscribe(observer1);
subject.subscribe(observer2);

subject.notify('Hello observers!'); // 两个观察者都会收到通知

// 实际应用:事件系统、状态管理(如Redux)、数据绑定
相关推荐
ssshooter6 小时前
看完就懂 useSyncExternalStore
前端·javascript·react.js
Live000007 小时前
在鸿蒙中使用 Repeat 渲染嵌套列表,修改内层列表的一个元素,页面不会更新
前端·javascript·react native
柳杉7 小时前
使用Ai从零开发智慧水利态势感知大屏(开源)
前端·javascript·数据可视化
球球pick小樱花8 小时前
游戏官网前端工具库:海内外案例解析
前端·javascript·css
喝水的长颈鹿8 小时前
【大白话前端 02】网页从解析到绘制的全流程
前端·javascript
静水流深_沧海一粟8 小时前
04 | 别再写几十个参数的构造函数了——建造者模式
设计模式
用户14536981458788 小时前
VersionCheck.js - 让前端版本更新变得简单优雅
前端·javascript
codingWhat8 小时前
整理「祖传」代码,就是在开发脚手架?
前端·javascript·node.js
StarkCoder8 小时前
从UIKit到SwiftUI的迁移感悟:数据驱动的革命
设计模式
码路飞8 小时前
写了个 AI 聊天页面,被 5 种流式格式折腾了一整天 😭
javascript·python