MST
星途 面试题库

面试题:Node.js项目结构设计中的模块划分原则

在Node.js项目结构设计中,模块划分是很重要的一部分,请阐述你理解的模块划分原则,并且举例说明如何依据这些原则来划分一个简单的文件上传服务项目的模块。
18.6万 热度难度
前端开发Node.js

知识考点

AI 面试

面试题答案

一键面试

模块划分原则

  1. 单一职责原则:每个模块应该有且仅有一个明确的职责,功能上做到高内聚。例如,用户认证模块只负责处理用户登录、注册、验证等与认证相关的操作,不掺杂其他业务逻辑。
  2. 低耦合原则:模块之间的依赖关系应尽量简单且松散,降低相互影响。比如,数据访问层模块与业务逻辑层模块之间,通过清晰的接口进行交互,业务逻辑层无需关心数据访问层具体如何连接数据库和执行查询。
  3. 可复用性原则:设计模块时要考虑其通用性,使其能在不同场景下复用。像日志记录模块,无论在文件上传服务还是其他项目功能模块中,都可以复用该模块来记录日志。
  4. 粒度适中原则:模块既不能划分得过于庞大,导致功能复杂难以维护;也不能过于细碎,造成模块间关系错综复杂。例如,将文件上传服务中的文件验证、文件存储等相关功能合并在一个合理粒度的“文件处理”模块中,而不是将文件验证又细分为多个极其微小的模块。

文件上传服务项目模块划分示例

  1. 路由模块
    • 职责:负责处理HTTP请求的路由,将不同的上传请求(如单文件上传、多文件上传)映射到相应的处理函数。
    • 代码示例
const express = require('express');
const router = express.Router();
const uploadController = require('../controllers/uploadController');

router.post('/single', uploadController.singleUpload);
router.post('/multiple', uploadController.multipleUpload);

module.exports = router;
  1. 控制器模块(uploadController)
    • 职责:处理文件上传的业务逻辑,如调用文件验证模块、文件存储模块等,并返回相应的响应给客户端。
    • 代码示例
const fileValidator = require('../utils/fileValidator');
const fileStorage = require('../utils/fileStorage');

const singleUpload = (req, res) => {
    const isValid = fileValidator.validateSingleFile(req.file);
    if (!isValid) {
        return res.status(400).send('Invalid file');
    }
    const result = fileStorage.storeSingleFile(req.file);
    res.send(result);
};

const multipleUpload = (req, res) => {
    const isValid = fileValidator.validateMultipleFiles(req.files);
    if (!isValid) {
        return res.status(400).send('Invalid files');
    }
    const results = fileStorage.storeMultipleFiles(req.files);
    res.send(results);
};

module.exports = {
    singleUpload,
    multipleUpload
};
  1. 文件验证模块(fileValidator)
    • 职责:负责验证上传文件的格式、大小等是否符合要求。
    • 代码示例
const MAX_FILE_SIZE = 1024 * 1024; // 1MB

const validateSingleFile = (file) => {
    if (!file) return false;
    if (file.size > MAX_FILE_SIZE) return false;
    const validExtensions = ['.jpg', '.png', '.pdf'];
    const fileExtension = file.originalname.split('.').pop().toLowerCase();
    return validExtensions.includes(`.${fileExtension}`);
};

const validateMultipleFiles = (files) => {
    if (!Array.isArray(files)) return false;
    return files.every(file => validateSingleFile(file));
};

module.exports = {
    validateSingleFile,
    validateMultipleFiles
};
  1. 文件存储模块(fileStorage)
    • 职责:负责将上传的文件存储到指定的位置(如本地磁盘、云存储等)。
    • 代码示例
const fs = require('fs');
const path = require('path');

const UPLOAD_DIR = path.join(__dirname, '../uploads');

const ensureDirExists = () => {
    if (!fs.existsSync(UPLOAD_DIR)) {
        fs.mkdirSync(UPLOAD_DIR);
    }
};

const storeSingleFile = (file) => {
    ensureDirExists();
    const filePath = path.join(UPLOAD_DIR, file.originalname);
    fs.writeFileSync(filePath, file.buffer);
    return `File ${file.originalname} stored successfully`;
};

const storeMultipleFiles = (files) => {
    ensureDirExists();
    const results = [];
    files.forEach(file => {
        const filePath = path.join(UPLOAD_DIR, file.originalname);
        fs.writeFileSync(filePath, file.buffer);
        results.push(`File ${file.originalname} stored successfully`);
    });
    return results;
};

module.exports = {
    storeSingleFile,
    storeMultipleFiles
};
  1. 配置模块
    • 职责:管理项目的各种配置信息,如文件上传的最大大小、存储路径等,方便在不同环境下进行调整。
    • 代码示例
module.exports = {
    maxFileSize: 1024 * 1024,
    uploadDir: path.join(__dirname, '../uploads')
};

通过以上模块划分,每个模块专注于自己的职责,模块之间耦合度低,同时具有一定的复用性,便于项目的开发、维护和扩展。