likes
comments
collection
share

深入 Node.js:五大设计模式必备指南本文探讨了 Node.js 中五种流行的设计模式,包括单例模式、工厂模式、观察

作者站长头像
站长
· 阅读数 53

我最近研究了 Node.js 中一些流行的设计和架构模式。尽管我的主要关注点在前端开发,但在这个过程中,我发现这些模式与我熟悉的前端框架有很多相似之处。这让我意识到,自己在日常开发中已经不知不觉地应用了这些设计模式,只是以前没有特别去思考它们的具体用法。

设计模式种类繁多(真的非常多),因此在本文中,我选出了五种,准备详细介绍它们。

什么是设计模式?

设计模式是经过验证且实践证明的解决方案,用于解决开发者在日常工作中遇到的问题。这些模式有助于推广最佳实践,并为设计和开发软件架构提供结构化的方法。通过使用这些模式,软件工程师能够构建可维护、安全且稳定的系统。

由于 Node.js 的灵活性,它并不强制开发者遵循特定的设计模式,而是给予选择所需模式的自由。因此,我认为这正是它今天被广泛使用的原因之一(顺便说一下,这也要归功于 JavaScript)。

Node.js 中的五种流行设计模式

以下是我选择的五种我喜欢的设计模式。

单例模式

单例模式主要关注只能有一个实例的类,并提供对该实例的全局访问。在 Node.js 中,模块可以被缓存并在整个应用程序中共享,从而提高资源的效率。一个常见的单例模式示例是用于连接特定第三方服务(如数据库、缓存服务、电子邮件提供商等)的模块,这在 Nest.js 框架中被广泛使用。

class Redis {
  constructor() {
    this.connection = null;
  }

  static getInstance() {
    if (!Redis.instance) {
      Redis.instance = new Redis();
    }
    return Redis.instance;
  }

  connect() {
    this.connection = 'Redis 已连接';
  }
}

使用示例:

const redisOne = Redis.getInstance();
const redisTwo = Redis.getInstance();

console.log(redisOne === redisTwo); // 结果为 `true`

redisOne.connect();

console.log(redisOne.connection); // 'Redis 已连接'
console.log(redisTwo.connection); // 'Redis 已连接'

这种方法确保只有一个 Redis 连接,从而防止连接的重复。

工厂模式

工厂模式允许你在不指定将要创建的对象类的情况下生成新对象。它抽象化了对象的创建,从而提高代码的可读性和可重用性:

class Character {
  constructor(type, health) {
    this.type = type;
    this.health = health;
  }
}

class CharacterFactory {
  createCharacter(name) {
    switch(name) {
      case 'mage': 
        return new Character('强大的法师', 8);
      case 'warrior':
        return new Character('勇敢的战士', 10);
      case 'rogue':
        return new Character('狡猾的盗贼', 9);
      default:
        return new Error('未知角色');
    }
  }
}

使用示例:

const characterFactory = new CharacterFactory();

const mage = characterFactory.createCharacter('mage');
const warrior = characterFactory.createCharacter('warrior');

console.log(mage.type); // 强大的法师
console.log(warrior.type); // 勇敢的战士

这种方法使得使用这个工厂的消费者能够使用工厂代码,而不是直接使用 Character 类的构造函数。

观察者模式

观察者模式的核心在于,有一个管理依赖元素(称为观察者)列表的实体,当状态改变时,它会通知这些观察者。该模式在 Vue.js 框架中被广泛应用,可以这样实现:

class Topic {
  constructor() {
    this.observers = []; 
  }

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

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

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

class Observer {
  constructor(name) {
    this.name = name;
  }

  update(data) {
    console.log(`${this.name} 收到了 ${data}`);
  }
}

使用示例:

const topic = new Topic();

const observer1 = new Observer('观察者 1');
const observer2 = new Observer('观察者 2');

topic.subscribe(observer1);
topic.subscribe(observer2);

topic.notify('你好,世界');
// 观察者 1 收到 你好,世界 
// 观察者 2 收到 你好,世界

topic.unsubscribe(observer2);

topic.notify('你好,再见');
// 观察者 1 收到 你好,再见

这是一个非常有用的模式,适用于事件处理和异步工作流,它允许更新多个对象,而不将发布者与订阅者耦合在一起。

装饰者模式

装饰者模式适用于在不影响初始实例的情况下,扩展现有功能。该模式在 Nest.jsTypeScript 的全面支持下得到了广泛应用,在普通的 Node.js 中同样适用:

class Character {
  constructor() {
    this.endurance = 10;
  }

  getEndurance() {
    return this.endurance;
  }
}

class CharacterActions {
  constructor(character) {
    this.character = character;
  }

  attack() {
    this.character.endurance -= 2;
  }

  rest() {
    this.character.endurance += 1; 
  }
}

使用示例:

const character = new Character();

console.log(character.getEndurance()); // 10

const characterWithActions = new CharacterActions(character);

characterWithActions.attack(); // - 2
characterWithActions.rest(); // + 1

console.log(characterWithActions.character.getEndurance()); // 9

通过使用这个模式,我们可以轻松扩展现有类,而不影响它们的核心功能。

依赖注入模式

在依赖注入模式中,类或模块从外部源接收依赖,而不是在内部注册这些依赖。这种方法允许将系统中的某些可重用元素提取出来,以便于测试和维护。这种模式在 Nest.js 框架中得到了广泛应用。可以通过以下方式实现:

class UserService {
  constructor(databaseService, loggerService) {
    this.db = databaseService;
    this.logger = loggerService;
  }

  async getUser(userId) {
    const user = await this.db.findUserById(userId);
    this.logger.log(`获取用户 ${user.name}`);
    return user;
  }
}

使用示例:

const databaseService = new Database();
const loggerService = new Logger();

const userService = new UserService(databaseService, loggerService);

userService.getUser(1);

这种方法允许你将系统中的元素提取为独立的实体,可以在需要时进行注入。

总结

通过这五种设计模式的介绍,可以看到它们在 Node.js 开发中的重要性。这些模式不仅提高了代码的可维护性和可读性,还使得开发者能够以更结构化的方式解决问题。希望这些模式能对你的开发工作有所帮助!

转载自:https://juejin.cn/post/7425974185320546331
评论
请登录