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)、数据绑定
相关推荐
某公司摸鱼前端3 小时前
uniapp socket 封装 (可拿去直接用)
前端·javascript·websocket·uni-app
要加油哦~3 小时前
vue | 插件 | 移动文件的插件 —— move-file-cli 插件 的安装与使用
前端·javascript·vue.js
wen's5 小时前
React Native 0.79.4 中 [RCTView setColor:] 崩溃问题完整解决方案
javascript·react native·react.js
黄雪超5 小时前
JVM——函数式语法糖:如何使用Function、Stream来编写函数式程序?
java·开发语言·jvm
ThetaarSofVenice5 小时前
对象的finalization机制Test
java·开发语言·jvm
思则变5 小时前
[Pytest] [Part 2]增加 log功能
开发语言·python·pytest
vvilkim5 小时前
Electron 自动更新机制详解:实现无缝应用升级
前端·javascript·electron
vvilkim5 小时前
Electron 应用中的内容安全策略 (CSP) 全面指南
前端·javascript·electron
GodKeyNet5 小时前
设计模式-模板模式
设计模式·模板模式
lijingguang5 小时前
在C#中根据URL下载文件并保存到本地,可以使用以下方法(推荐使用现代异步方式)
开发语言·c#