Node.js中常用的设计模式有哪些?
本文由葡萄城技术团队首发。转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具、解决方案和服务,赋能开发者。
设计模式简介
设计模式是由经验丰富的程序员在日积月累中抽象出的用以解决通用问题的可复用解决方案,它提供了标准化的代码设计方案提升开发体验。Node.js 作为一款用来构建可扩展高性能应用的流行平台,自然也遵循设计模式解决通用问题。本文中,我们将讨论 Node.js 中设计模式的重要性并提供一些代码示例。

构建 Node.js 应用为何需要设计模式
设计模式为软件开发提供了一套标准化的解决方案。构建 Node.js 应用时,善用设计模式能够帮助开发者提升代码质量,节约开发时间,减少出错几率。同时也方便开发人员之间的沟通交流。

示例代码
单例模式
该模式用来保证特定的类在整个应用中只能创建唯一实例。Node.js 中,单例模式可以保证在同一个应用中,每个模块只有唯一实例。
class Singleton {
constructor() {
if (Singleton.instance) {
return Singleton.instance;
}
Singleton.instance = this;
}
// Your code here
}
module.exports = Singleton;
工厂模式
工厂模式用来在不暴露实现逻辑的情况下创建对象。在 Node.js 中,使用工厂模式可以根据用户输入创建不同类型的实例。
class Car {
constructor(name) {
this.name = name;
}
drive() {
console.log(`Driving ${this.name}`);
}
}
class CarFactory {
static create(name) {
return new Car(name);
}
}
const car1 = CarFactory.create("BMW");
const car2 = CarFactory.create("Audi");
car1.drive(); // Driving BMW
car2.drive(); // Driving Audi
观察者模式
观察者模式通过维护一个被观察对象列表,实现当对象发生改变时发出通知。在 Node.js中,该设计模式用来管理事件和回调。
class EventObserver {
constructor() {
this.observers = [];
}
subscribe(fn) {
this.observers.push(fn);
}
unsubscribe(fn) {
this.observers = this.observers.filter(subscriber => subscriber !== fn);
}
notify(data) {
this.observers.forEach(observer => observer(data));
}
}
const eventObserver = new EventObserver();
eventObserver.subscribe(data => console.log(`Subscribed to ${data}`));
eventObserver.notify("some data");
依赖注入模式
在本案例中,定义了一个依赖database 对象的UserService 类。通过将 database 传给 UserService 的构造函数,实现在不修改 UserService 的前提下操作不同数据库对象。
class UserService {
constructor(database) {
this.database = database;
}
getUser(id) {
return this.database.query(`SELECT * FROM users WHERE id = ${id}`);
}
}
module.exports = UserService;
Promise 模式
在本案例中,通过 fs.promises 模块异步读取文件。readFile 函数返回一个 promise 对象,该 promise对象成功时可以通过 then 方法获取文件内容,失败时可以通过 catch 方法获取错误信息。
const fs = require('fs').promises;
function readFile(filePath) {
return fs.readFile(filePath, 'utf8');
}
readFile('example.txt')
.then(data => {
console.log(data);
})
.catch(error => {
console.error(error);
});
Node.js 内建模块中的设计模式
默认情况下,Node.js 本身在其功能中不依赖任何特定的设计模式,但它提供了遵循常见设计模式的内置模块。Node.js 中一些常用的设计模式包括:
模块模式
Node.js 默认使用模块模式将代码组织成可复用、可维护的模块。在 Node.js 中,每个文件都被视为一个模块,开发人员可以使用 require 和 module.exports 语句在文件之间导出或导入代码。
const fs = require('fs');
// 异步读取文件
fs.readFile('file.txt', 'utf8', (err, data) => {
if (err) throw err;
console.log(data);
});
// 同步读取文件
const data = fs.readFileSync('file.txt', 'utf8');
console.log(data);
// 写入文件
fs.writeFile('file.txt', 'Hello, World!', (err) => {
if (err) throw err;
console.log('文件已写入');
});
事件驱动模式
Node.js 使用事件驱动模式来处理 I/O 操作,如向文件或网络套接字读取和写入数据。事件驱动模式基于观察者模式,允许开发人员创建事件发射器,以便在某些事件发生时通知侦听器。
// 模块定义
const myModule = (function () {
// 私有成员
const privateVar = 'Hello, World!';
function privateMethod() {
console.log(privateVar);
}
// 公有成员
return {
publicMethod: function () {
privateMethod();
},
publicVar: 'I am public'
};
})();
// 使用模块
myModule.publicMethod(); // 输出 'Hello, World!'
console.log(myModule.publicVar); // 输出 'I am public'
回调模式
Node.js 使用回调模式来处理异步操作,如读写文件或网络请求。回调模式基于观察者模式,允许开发人员将函数作为参数传递,以便在操作完成时执行。
function fetchData(callback) {
// 模拟异步数据获取
setTimeout(() => {
const data = 'Hello, World!';
callback(null, data); // 第一个参数为错误对象,第二个参数为返回的数据
}, 2000);
}
function processData(err, data) {
if (err) {
console.error('出错了:', err);
return;
}
console.log('处理数据:', data);
}
fetchData(processData);
中间件模式
中间件是 Express.js 等 Node.js 框架中常用的设计模式。中间件函数是在管道中执行的函数,其中每个函数都可以在将请求或响应对象传递到下一个函数之前修改它们。中间件可用于身份验证、日志记录、错误处理等任务。
// 中间件函数1
function middleware1(req, res, next) {
console.log('执行中间件1');
// 在这里可以对 req 和 res 进行处理
next(); // 调用 next() 将控制权传递给下一个中间件
}
// 中间件函数2
function middleware2(req, res, next) {
console.log('执行中间件2');
// 在这里可以对 req 和 res 进行处理
next(); // 调用 next() 将控制权传递给下一个中间件
}
// 最终处理函数
function finalHandler(req, res) {
console.log('执行最终处理函数');
// 在这里进行最终的请求处理和响应
res.end('Hello, World!');
}
// 使用中间件
function handleRequest(req, res) {
middleware1(req, res, () => {
middleware2(req, res, () => {
finalHandler(req, res);
});
});
}
// 创建服务器并处理请求
const http = require('http');
const server = http.createServer(handleRequest);
server.listen(3000, 'localhost', () => {
console.log('服务器已启动');
});
依赖注入模式
依赖注入(DI)模式是一种用于管理对象之间依赖关系的设计模式。在 Node.js 中,DI 可用于将依赖项注入到模块中,使它们更加模块化和可重用。DI 可以使用构造函数注入、属性注入或方法注入等技术来实现。
// 用户服务模块
class UserService {
constructor() {
this.users = [];
}
addUser(user) {
this.users.push(user);
}
getUsers() {
return this.users;
}
}
// 用户控制器模块(依赖于用户服务模块)
class UserController {
constructor(userService) {
this.userService = userService;
}
addUser(user) {
this.userService.addUser(user);
}
getUsers() {
return this.userService.getUsers();
}
}
// 使用依赖注入创建用户控制器实例
const userService = new UserService();
const userController = new UserController(userService);
// 在用户控制器中添加用户并获取用户列表
userController.addUser('John');
userController.addUser('Mary');
console.log(userController.getUsers()); // 输出:['John', 'Mary']
Promise模式
Promise模式是一种设计模式,用于以更结构化和类似同步的方式处理异步操作。Promise 是表示异步操作最终完成或失败的对象,允许开发人员通过将异步操作连接在一起来编写更具可读性和可维护性的代码。
// 使用 Promise 封装异步函数
function getUserById(id) {
return new Promise((resolve, reject) => {
setTimeout(() => {
const user = { id, name: 'John' };
resolve(user);
}, 1000);
});
}
// 调用异步函数并使用 Promise 链式调用处理结果
getUserById(1)
.then(user => {
console.log(user);
return getUserById(2);
})
.then(user => {
console.log(user);
})
.catch(err => {
console.error(err);
});
总结
设计模式提供了一种结构化方法来解决 Node.js 中的常见编程问题。它们帮助开发人员编写更好、可维护和可扩展的代码。设计模式还为开发人员之间的交流提供了“标准词汇”。设计模式对于使用 Node.js 编写高质量代码至关重要,如果您想了解更多关于前端表格控件的知识,欢迎点击这里。
扩展链接:
React + Springboot + Quartz,从0实现Excel报表自动化
Node.js中常用的设计模式有哪些?的更多相关文章
- node.js中常用的fs文件系统
fs文件系统模块对于系统文件及目录进行一些读写操作. 模块中的方法均有异步和同步版本,例如读取文件内容的函数有异步的 fs.readFile() 和同步的 fs.readFileSync(). 异步的 ...
- js 中常用的设计模式
常用的设计模式: 工厂方法模式.单例模式.适配器模式.组合模式.迭代子模式 (23种设计模式) 总体来说设计模式分为三大类: ①创建型模式 共五种:工厂方法模式.抽象工厂模式.单例模式.建造者模式.原 ...
- Node.js中的模块化
每天一篇文章来记录记录自己的成长吧.大二,该静心了.加油~ 好了,废话不多说,今天说说nodejs中的模块化.(注:此文为自己对书nodejs实战的总结) nodejs一个重要的特性就是模块化,模块就 ...
- Node.js:常用工具util
概要:本篇博客的主要内容是介绍node.js的常用工具util. 1.util.inherits util.inherits(constructor,superConstructor)是一个实现对象间 ...
- Node.js中环境变量process.env详解
Node.js中环境变量process.env详解process | Node.js API 文档http://nodejs.cn/api/process.html官方解释:process 对象是一个 ...
- node.js中的回调
同步和阻塞:这两个术语可以互换使用,指的是代码的执行会在函数返回之前停止.如果某个操作阻塞,那么脚本就无法继续,这意味着必须等待. 异步和非阻塞:这两个术语可以互换使用,指的是基于回调的.允许脚本并行 ...
- Cookie和Session在Node.JS中的实践(二)
Cookie和Session在Node.JS中的实践(二) cookie篇在作者的上一篇文章Cookie和Session在Node.JS中的实践(一)已经是写得算是比较详细了,有兴趣可以翻看,这篇是s ...
- 理解 Node.js 中 Stream(流)
Stream(流) 是 Node.js 中处理流式数据的抽象接口. stream 模块用于构建实现了流接口的对象. Node.js 提供了多种流对象. 例如,对 HTTP 服务器的request请求和 ...
- 前端走进机器学习生态,在 Node.js 中使用 Python
这次给大家带来一个好东西,它的主要用途就是能让大家在 Node.js 中使用 Python 的接口和函数.可能你看到这里会好奇,会疑惑,会不解,我 Node.js 大法那么好,干嘛要用 Python ...
- js中常用追加元素的几种方法
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
随机推荐
- 基于GPT搭建私有知识库聊天机器人(二)环境安装
1.需要安装的包 pip3 install flask //python开发web框架 pip3 install langchain //LLM开发框架 pip3 install openai //L ...
- 浅析switch和if(开发中这两者的优缺点;分析出优缺点在使用就能更确定自己需要使用哪个函数了)
分析 Switch 相较于 if 的优点 1.switch 执行效率 高于 if 的执行效率 分析: switch是在编译阶段将子函数的地址和判断条件绑定了,只要直接将a的直接映射到子函数地址去执 ...
- python3.8下安装robotframework历险记
首先非常感谢本文章博主,极大的给与我可以装好的信心(差点要重装python)https://blog.csdn.net/qq_21583077/article/details/107848409?sp ...
- S32Kxxx bootloader之LIN bootloader
了解更多关于bootloader 的C语言实现,请加我Q扣: 1273623966 (验证信息请填 bootloader),欢迎咨询或定制bootloader(在线升级程序). 上一次发布博文到如今既 ...
- 深度学习(五)——DatadLoader的使用
一.DataLoader简介 官网地址: torch.utils.data - PyTorch 2.0 documentation 1. DataLoder类 class torch.utils.da ...
- Cilium系列-6-从地址伪装从IPtables切换为eBPF
系列文章 Cilium 系列文章 前言 将 Kubernetes 的 CNI 从其他组件切换为 Cilium, 已经可以有效地提升网络的性能. 但是通过对 Cilium 不同模式的切换/功能的启用, ...
- 关于No changes detected
查看app在settings.py文件夹中是否有注册.
- 下一代MES系统架构分析与选型参考
本文分享自华为云社区<工业互联网系列(十一):下一代MES系统架构分析与选型参考>,作者:云起MAE . 目前国内制造执行系统MES市场尚处于"功能机"混战年代,市场集 ...
- selenium报错:This version of ChromeDriver only supports Chrome version 109 Current browser version is 112.0.5615.49...解决办法
前言:跟GPT交互,让其写一段代码,执行失败.经过排查验证,GPT写的代码没有问题,是本地环境问题. 执行报错: selenium.common.exceptions.SessionNotCreate ...
- 操作系统实验——系统调用:获取当前进程pid和ppid
目录 一.题目介绍 二.实验思路 三.核心代码 四.遇到的问题及一些解决方法 五.参考文献 PS:博客只是提供一个简要的思路,互相学习. 一.题目介绍 显示当前进程的pid和父进程的pid,主要考察如 ...