一、为什么需要分层架构

想象一下你正在装修房子。如果把水电管道、瓷砖、家具全都混在一起施工,不仅后期维护困难,连换个灯泡都可能要拆墙。Node.js应用开发也是同样的道理,好的分层设计能让你的代码像精装房一样模块清晰。

分层模式的核心价值在于:

  1. 关注点分离:每层只处理特定职责
  2. 降低耦合度:修改某层不会影响其他层
  3. 便于协作:不同开发者可以并行开发不同层次
  4. 可测试性:每层都可以单独进行单元测试
// 反面教材:所有逻辑混在一起的代码
app.post('/users', async (req, res) => {
  // 1. 验证输入
  if(!req.body.name) return res.status(400).send('Name required')
  
  // 2. 数据库操作
  const user = await db.query('INSERT INTO users...')
  
  // 3. 发送响应
  res.json({ id: user.insertId })
  
  // 4. 记录日志
  fs.appendFileSync('log.txt', `User created at ${new Date()}`)
  
  // 5. 发送欢迎邮件
  await mailer.sendWelcomeEmail(user.email)
})

二、经典三层架构实践

2.1 表现层(Presentation Layer)

处理HTTP请求和响应,就像餐厅的前台接待。我们使用Express框架作为技术栈示例:

// controllers/userController.js
const userService = require('../services/userService')

module.exports = {
  async createUser(req, res, next) {
    try {
      // 1. 接收并校验参数
      const { name, email } = req.body
      if (!name || !email) {
        return res.status(400).json({ error: 'Missing parameters' })
      }
      
      // 2. 调用服务层
      const newUser = await userService.createUser(name, email)
      
      // 3. 返回标准化响应
      res.status(201).json({
        data: newUser,
        meta: { timestamp: new Date() }
      })
    } catch (err) {
      next(err) // 4. 错误处理交给中间件
    }
  }
}

2.2 业务逻辑层(Service Layer)

这是系统的"大脑",处理核心业务逻辑:

// services/userService.js
const userRepository = require('../repositories/userRepository')
const mailService = require('./mailService')

module.exports = {
  async createUser(name, email) {
    // 1. 业务规则校验
    if (name.length > 50) {
      throw new Error('Name too long')
    }
    
    // 2. 调用仓储层
    const user = await userRepository.create({ name, email })
    
    // 3. 触发后续流程
    await mailService.sendWelcomeEmail(email)
    
    // 4. 返回处理结果
    return {
      id: user.id,
      name: user.name,
      initials: name[0].toUpperCase()
    }
  }
}

2.3 数据访问层(Repository Layer)

相当于系统的"记忆中枢",封装所有数据库操作。这里使用Sequelize作为ORM示例:

// repositories/userRepository.js
const { User } = require('../models')

module.exports = {
  async create(userData) {
    return await User.create(userData)
  },
  
  async findById(id) {
    return await User.findByPk(id, {
      attributes: ['id', 'name', 'email']
    })
  },
  
  async update(id, updates) {
    const user = await User.findByPk(id)
    if (!user) throw new Error('User not found')
    return await user.update(updates)
  }
}

三、进阶分层技巧

3.1 DTO(数据传输对象)模式

在不同层之间传递数据时,使用专门的对象来封装:

// dtos/UserDTO.js
class UserDTO {
  constructor(user) {
    this.id = user.id
    this.fullName = `${user.firstName} ${user.lastName}`
    this.avatar = user.profileImage || '/default-avatar.png'
  }
  
  toJSON() {
    return {
      id: this.id,
      name: this.fullName,
      avatar: this.avatar
    }
  }
}

// 在控制器中使用
const user = await userService.getUser(id)
res.json(new UserDTO(user))

3.2 依赖注入实现解耦

使用构造函数注入依赖,方便测试和替换实现:

// services/paymentService.js
class PaymentService {
  constructor(paymentGateway, logger) {
    this.gateway = paymentGateway
    this.logger = logger
  }
  
  async charge(amount, card) {
    try {
      const result = await this.gateway.charge(amount, card)
      this.logger.info(`Charged ${amount} to card ${card.last4}`)
      return result
    } catch (err) {
      this.logger.error('Payment failed', err)
      throw err
    }
  }
}

// 使用时
const stripeGateway = require('./gateways/stripe')
const logger = require('./utils/logger')
const paymentService = new PaymentService(stripeGateway, logger)

四、实战中的注意事项

  1. 层间通信规范:

    • 上层可以调用下层,但禁止反向调用
    • 同级层之间避免直接依赖
    • 跨层调用必须通过中间层传递
  2. 错误处理策略:

// middleware/errorHandler.js
module.exports = function(err, req, res, next) {
  // 业务错误
  if (err instanceof BusinessError) {
    return res.status(400).json({
      error: err.message,
      code: err.code
    })
  }
  
  // 系统错误
  console.error(err)
  res.status(500).json({
    error: 'Internal Server Error',
    requestId: req.id
  })
}
  1. 目录结构建议:
src/
├── config/         # 配置文件
├── controllers/    # 控制器层
├── services/       # 业务逻辑层 
├── repositories/   # 数据访问层
├── models/         # 数据模型
├── dtos/           # 数据传输对象
├── middleware/     # 中间件
├── utils/          # 工具函数
└── app.js          # 应用入口
  1. 性能优化技巧:
    • 在控制器层做参数校验,尽早失败
    • 服务层实现业务缓存逻辑
    • 仓储层处理批量操作和查询优化

分层架构就像给代码穿上分体式服装,既保持了整体协调性,又方便单独更换某个部件。刚开始可能会觉得多写几层代码有点麻烦,但当项目规模超过1万行代码后,你就会感谢当初的选择。记住,好的架构不是一次性设计出来的,而是在不断重构中逐步演化形成的。