JavaScript设计模式与代码示例

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

JavaScript 设计模式与示例



设计模式 (design patterns) 是软件开发中常见问题的经过验证的解决方案。对于 JavaScript 开发者来说,了解设计模式尤其重要,因为该语言具有灵活的对象模型,并广泛用于客户端和服务器端 (Node.js)。在本文中,我们将通过 JavaScript 的实际示例来解析四种关键设计模式。



为什么要学习设计模式?

设计模式有助于:

  • 简化代码的维护和扩展
  • 使代码更具可读性和可预测性
  • 避免"重复造轮子"
  • 改善团队沟通(通用语言)


1. Singleton (单例模式)

Singleton 模式确保一个类只有一个实例,并提供一个全局访问点。在 Node.js 中,此模式常用于数据库连接、配置管理或日志记录。



class DatabaseConnection {  constructor() {    if (DatabaseConnection.instance) {      return DatabaseConnection.instance;    }    this.connection = null;    DatabaseConnection.instance = this;  }

connect() { // 模拟数据库连接 this.connection = "connected"; console.log("数据库连接已建立"); }

query(sql) { if (!this.connection) { throw new Error("没有数据库连接"); } console.log(`执行查询: ${sql}`); return { data: [] }; }}

// 使用const db1 = new DatabaseConnection();const db2 = new DatabaseConnection();

db1.connect();console.log(db1 === db2); // true - 两者指向同一个实例db2.query("SELECT * FROM users");


何时使用:管理共享资源(数据库、配置、缓存)。注意:过度使用可能导致代码高度耦合。



2. Factory (工厂模式)

Factory Method 定义创建对象的接口,但允许子类更改所创建对象的类型。在 JavaScript 中,这通常通过普通函数或类来实现。



class User {  constructor(name, role) {    this.name = name;    this.role = role;  }

getPermissions() { return []; }}

class Admin extends User { getPermissions() { return ["read", "write", "delete", "manage"]; }}

class Editor extends User { getPermissions() { return ["read", "write"]; }}

class Viewer extends User { getPermissions() { return ["read"]; }}

// 工厂class UserFactory { createUser(name, role) { switch (role) { case "admin": return new Admin(name, role); case "editor": return new Editor(name, role); case "viewer": return new Viewer(name, role); default: throw new Error("未知角色"); } }}

// 使用const factory = new UserFactory();const admin = factory.createUser("安娜", "admin");const viewer = factory.createUser("伊万", "viewer");

console.log(admin.getPermissions()); // ["read", "write", "delete", "manage"]console.log(viewer.getPermissions()); // ["read"]


优点:集中管理对象创建,易于添加新类型,隐藏实例化逻辑。



3. Observer (观察者模式)

Observer 模式定义了对象之间的一对多依赖关系。当一个对象(主题)改变状态时,所有依赖对象(观察者)都会自动收到通知。这是 Node.js 中事件驱动编程的基础。



class EventEmitter {  constructor() {    this.events = {};  }

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

emit(eventName, ...args) { const listeners = this.events[eventName]; if (listeners) { listeners.forEach(listener => listener(...args)); } }

off(eventName, listenerToRemove) { const listeners = this.events[eventName]; if (listeners) { this.events[eventName] = listeners.filter( listener => listener !== listenerToRemove ); } }}

// 使用const emitter = new EventEmitter();

const onUserLogin = (username) => { console.log(`用户 ${username} 已登录`);};

const onAdminLogin = (username) => { console.log(`管理员 ${username} 已登录`);};

emitter.on("login", onUserLogin);

emitter.on("login", onAdminLogin);

emitter.emit("login", "Анна");// 输出:// 用户 Анна 已登录// 管理员 Анна 已登录

emitter.off("login", onAdminLogin);

emitter.emit("login", "Иван");// 输出:// 用户 Иван 已登录


何时使用:事件处理系统、实时更新、MVC 架构。注意:大量观察者可能导致性能问题。



4. Module (模块模式)

Module 模式是 JavaScript 中最常用的模式之一。它允许将代码封装在单独的作用域中,隐藏内部实现细节,仅暴露公共接口。在现代 JavaScript 中,这通过 ES modules (import/export) 实现,但经典实现使用 IIFE (Immediately Invoked Function Expression)。



// 使用 IIFE 的经典模块模式const UserModule = (function() {  // 私有变量  let users = [];  let nextId = 1;

// 私有函数 function validateUser(userData) { if (!userData.name || userData.name.length < 2) { throw new Error("用户名必须至少包含2个字符"); } return true; }

// 公共 API return { addUser(userData) { validateUser(userData); const user = { id: nextId++, name: userData.name, role: userData.role || "user", createdAt: new Date() }; users.push(user); return user; },

getUsers() { return [...users]; },

findUser(id) { return users.find(user => user.id === id) || null; },

deleteUser(id) { const index = users.findIndex(user => user.id === id); if (index !== -1) { return users.splice(index, 1)[0]; } return null; },

getCount() { return users.length; } };})();

// 使用const user1 = UserModule.addUser({ name: "Анна", role: "admin" });const user2 = UserModule.addUser({ name: "Иван" });

console.log(UserModule.getUsers());// 输出: [{ id: 1, name: 'Анна', role: 'admin', createdAt: ... }, { id: 2, name: 'Иван', role: 'user', createdAt: ... }]

console.log(UserModule.getCount()); // 2

// 无法访问私有变量console.log(UserModule.users); // undefinedconsole.log(UserModule.validateUser); // undefined


优点:封装、命名空间管理、避免全局作用域污染。现代替代方案:ES modules (import/export) 提供更原生的模块化支持。



总结

设计模式是每个 JavaScript 开发者工具包中的重要工具。它们不是严格的规则,而是可以根据具体任务进行调整的灵活解决方案。关键不是记住所有模式,而是理解它们解决的问题以及在项目中何时应用它们。



从 Singleton 和 Module 等简单模式开始,逐渐过渡到更复杂的模式,如 Observer 和 Factory。在实践中,您会发现许多现代框架和库(如 React、Vue、Express)已经在内部积极使用这些模式。



记住:好的代码不是使用最多模式的地方,而是使用最合适的模式来解决特定问题的地方。

博客

书籍推荐