Dependency Injection Analysis¶
重要性:⭐⭐⭐ 目标读者:架构师 / 高级开发者 关联:analysis/module-dependencies.md
1. 概览¶
本文档分析 Claude Code 的依赖注入(DI)模式。
5 主题: - DI 模式 - 实际实现 - 优点 - 缺点 - 改进方向
2. 5 大 DI 模式¶
2.1 构造注入¶
最常见。
2.2 Setter 注入¶
修改。
2.3 接口注入¶
interface Client {
call(req): Promise<res>
}
class Engine {
constructor(private client: Client) {}
}
抽象。
2.4 服务定位¶
查找。
2.5 依赖倒置¶
DIP。
3. Claude Code 的 DI 模式¶
3.1 实际模式:手工注入 + 全局单例¶
// 入口
const main = async () => {
const client = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY })
const tools = getTools()
// ...
const engine = new QueryEngine({ client, tools, ... })
}
手工 + 单例。
3.2 ToolUseContext 传递¶
// 工具通过 context 接收
async function Read(input, context: ToolUseContext) {
// context 含:client, store, appState, ...
}
context 模式。
3.3 Hooks 接收服务¶
hooks 模式。
3.4 zustand-style 状态¶
subscribe。
3.5 feature gate 替代¶
模块级。
4. 4 个 DI 关键文件¶
4.1 bootstrap/state.js¶
setter。
4.2 state/AppStateStore.ts¶
store。
4.3 Tool.ts¶
interface。
4.4 entrypoints/init.js¶
init。
5. 5 个优点¶
5.1 简单¶
手工注入,无 框架。
5.2 显式¶
依赖显式 在构造。
5.3 可测¶
可注入 mock。
5.4 无魔法¶
不依赖框架。
5.5 TS 友好¶
类型安全。
6. 5 个缺点¶
6.1 重复¶
重复。
6.2 深度传递¶
深。
6.3 全局状态¶
global。
6.4 测试 mock 复杂¶
mock。
6.5 重构风险¶
refactor。
7. 实际代码例子¶
7.1 ToolUseContext¶
interface ToolUseContext {
// 5 大类
agentId?: string
options: ToolUseContextOptions
abortController: AbortController
getAppState: () => AppState
setAppState: (updater) => void
// ... ~30 字段
}
async function Read(
input: { file_path: string },
context: ToolUseContext,
): Promise<ToolResult> {
const cwd = context.options.cwd
const appState = context.getAppState()
// ...
}
~30 字段 context。
7.2 单例 + setter¶
// state/AppStateStore.ts
let _store: AppState
export function getAppState(): AppState {
return _store
}
export function setAppState(updater: (prev: AppState) => AppState): void {
_store = updater(_store)
}
单例 + setter。
7.3 Hooks 服务定位¶
// hooks/useClaudeApi.ts
export function useClaudeApi() {
return useMemo(() => createClaudeApi(), [])
}
hook。
7.4 feature 模块注入¶
feature。
8. 5 个改进方向¶
8.1 引入 DI 容器¶
// tsyringe / inversify
import { container } from 'tsyringe'
container.register('Anthropic', { useValue: client })
容器。
8.2 抽象接口¶
interface IClaudeApi {
call(req): Promise<res>
}
// 实现可换
class AnthropicImpl implements IClaudeApi { ... }
class MockImpl implements IClaudeApi { ... }
interface。
8.3 Context 简化¶
// 30 字段 → 5 大类
interface Context {
auth: AuthContext
state: StateContext
tools: ToolsContext
// ...
}
分组。
8.4 Provider 模式¶
provider。
8.5 工厂模式¶
factory。
9. 5 个测试考虑¶
9.1 Mock client¶
const mockClient = {
call: jest.fn().mockResolvedValue({ ... })
}
const engine = new QueryEngine({ client: mockClient, ... })
mock。
9.2 In-memory state¶
test state。
9.3 工具 stub¶
stub。
9.4 集成测试¶
integration。
9.5 E2E¶
E2E。
10. 5 个常见问题¶
10.1 循环依赖¶
解决:lazy require / getter。
10.2 大 context¶
解决:分组 + interface。
10.3 难以 mock¶
解决:依赖注入。
10.4 测试慢¶
解决:mock + 简化。
10.5 重构难¶
解决:interface 隔离。
11. 5 个最佳实践¶
11.1 显式注入¶
显式。
11.2 小 context¶
小。
11.3 抽象接口¶
interface。
11.4 测试友好¶
test。
11.5 文档化¶
docs。
12. 与其他模式对比¶
| 模式 | 优点 | 缺点 |
|---|---|---|
| 手工注入 | 简单 | 重复 |
| DI 容器 | 集中 | 魔法 |
| Service Locator | 易用 | 全局 |
| Provider | 灵活 | 嵌套 |
| 手工 + 单例 | 显式 | 测试难 |
5 模式。
13. 关键 trade-off¶
4 维 trade-off。
14. 5 个 insight¶
14.1 Claude Code 选"手工 + 单例"¶
理由:简单、显式、TS 友好。
14.2 ToolUseContext 30 字段¶
多但合理——业务丰富。
14.3 feature gate 是 DI¶
变体——编译时注入。
14.4 没有 DI 容器¶
故意——避免魔法。
14.5 测试 mock 复杂¶
代价——手动 mock。
15. 总结¶
Dependency Injection Analysis = 5 主题 + 5 模式 + 5 优缺点。
核心: - 手工 + 单例 - ToolUseContext 30 字段 - feature gate 模块注入 - 5 改进方向
下一步: - 看 module-dependencies.md - 考虑 DI 容器 - 抽象接口