You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TypeScript中Dependency inversion与clean architecture优化:组合根设计咨询

基于Clean Architecture优化依赖注入与组合根设计

核心问题分析

你当前的代码存在两个关键问题:

  1. 领域层接口定义混淆:user.interface.ts和user-data.interface.ts的内容写反了,违反领域层实体定义规范
  2. 组合根职责不清晰:第二种方案将依赖注入逻辑放在Controller层,导致领域层依赖基础设施层,直接违反依赖倒置原则(高层模块不应依赖低层模块,二者都应依赖抽象)

符合Clean Architecture的优化方案

Clean Architecture的核心是依赖方向向内:领域层(最内层)不依赖任何外层,应用层依赖领域层,基础设施层依赖应用/领域层,组合根作为唯一的"外层向内"依赖入口,负责所有实例化与注入。

1. 修正领域层接口定义

先修正领域层的实体和数据传输对象接口,确保语义正确:

// domain/user.interface.ts
// 领域实体:User,代表业务核心对象
export interface User {
  id: string;
  name: string;
  email: string;
  // 其他业务属性
}
// domain/user-data.interface.ts
// 数据传输对象:UserData,用于接收外部输入的数据结构
export interface UserData {
  name: string;
  email: string;
  password: string;
  // 其他输入属性
}

2. 分离Controller的定义与实例化

Controller属于接口适配器层(Clean Architecture的外层),它应依赖应用层的用例抽象,而非自行实例化依赖。单独定义Controller类:

// adapters/controllers/user-controller.ts
import { CreateUserUseCase } from '../../domain/usecase.interface';
import { UserData } from '../../domain/user-data.interface';
import { User } from '../../domain/user.interface';

export class UserController {
  constructor(private readonly createUserUseCase: CreateUserUseCase) {}

  async createUser(userData: UserData): Promise<User> {
    return this.createUserUseCase.execute(userData);
  }
}

3. 优化组合根(app.ts)的职责

保留独立的app.ts作为组合根,这是符合Clean Architecture的正确做法——它是唯一允许跨层实例化对象的地方,负责串联所有依赖:

// app.ts
// 组合根:唯一负责依赖注入的入口
import { UserController } from './adapters/controllers/user-controller';
import CreateUserUseCaseImpl from './domain/create-user.usecase';
import MongoDBUserRepository from './infra/persistence/mongodb-user.repository';

// 从最底层的基础设施实例化,向上注入
const userRepository = new MongoDBUserRepository();
const createUserUseCase = new CreateUserUseCaseImpl(userRepository);
const userController = new UserController(createUserUseCase);

export { userController };

4. 调整基础设施层的依赖引入

确保基础设施层只依赖领域层的抽象,不反向依赖外层:

// infra/persistence/mongodb-user.repository.ts
import { UserRepository } from '../../domain/repository.interface';
import { User } from '../../domain/user.interface';
import { UserData } from '../../domain/user-data.interface';

export class MongoDBUserRepository implements UserRepository {
  async saveUser(userData: UserData): Promise<User> {
    // MongoDB具体实现逻辑
    const savedUser = {
      id: 'mock-id-123',
      ...userData
    };
    return savedUser;
  }
}

5. 调整HTTP入口的依赖引入

HTTP层(基础设施层的一部分)只需从组合根获取已实例化的Controller,无需关心依赖链:

// infra/http/main.ts
import express from 'express';
import { userController } from '../../app';
import { UserData } from '../../domain/user-data.interface';

const app = express();
app.use(express.json());

app.post('/users', async (req, res) => {
  const userData: UserData = req.body;

  try {
    const createdUser = await userController.createUser(userData);
    res.status(201).json(createdUser);
  } catch (error) {
    res.status(500).json({ error: 'Failed to create user.' });
  }
});

app.listen(3000, () => {
  console.log('Server running on port 3000');
});

优化后的分层依赖关系

  • 领域层:仅包含业务实体、用例接口、仓库接口,不依赖任何外层
  • 接口适配器层:Controller依赖领域层的用例抽象,不依赖基础设施
  • 基础设施层:MongoDB仓库实现依赖领域层的仓库接口,HTTP服务依赖组合根提供的Controller
  • 组合根(app.ts):唯一跨层实例化对象的地方,负责将所有依赖从外到内注入,完全符合依赖倒置原则

内容的提问来源于stack exchange,提问作者boojum

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 04:16:05