6.1 KiB
6.1 KiB
Tool V2 - 可拼接式设计
🎯 设计理念
核心原则
- 松耦合 - 工具之间通过接口通信,不直接依赖
- 可替换 - 任何工具都可以被同类工具替换
- 可组合 - 像乐高一样自由组合
- 依赖注入 - 通过服务名获取依赖,而非硬编码
📦 架构示意图
┌─────────────────────────────────────────┐
│ IToolContext (上下文) │
│ ┌─────────────┐ ┌───────────────┐ │
│ │ Data Store │ │ Service Bus │ │
│ └─────────────┘ └───────────────┘ │
└─────────────────────────────────────────┘
↑ ↑
│ │
┌────────┴────────┬───────┴────────┐
│ │ │
┌─────────┐ ┌──────────┐ ┌──────────┐
│ Tool A │ │ Tool B │ │ Tool C │
│provides │ │requires │ │provides │
│storage │ │storage │ │generator │
└─────────┘ └──────────┘ └──────────┘
💡 使用示例
场景1:使用MySQL存储
const toolManager = new ToolManager();
// 注册工具(顺序无关!)
toolManager.register(new CardGeneratorTool());
toolManager.register(new MySQLStorageTool()); // 提供storage
toolManager.register(new AccountGeneratorTool());
// 自动解决依赖并初始化
await toolManager.initializeAll();
// 使用
const context = toolManager.getContext();
const cardGen = context.getService<IGeneratorService>('card-generator');
const card = await cardGen.generate();
场景2:切换到Redis存储(只需改一行!)
const toolManager = new ToolManager();
toolManager.register(new CardGeneratorTool());
toolManager.register(new RedisStorageTool()); // 替换成Redis!
toolManager.register(new AccountGeneratorTool());
await toolManager.initializeAll(); // 其他代码完全不用改
🔌 可拼接的优势
1. 完全解耦
// ❌ 旧设计 - 耦合
class CardGenerator {
constructor(private db: MySQLDatabase) {} // 硬编码依赖MySQL
}
// ✅ 新设计 - 解耦
class CardGeneratorTool {
readonly requires = ['storage']; // 只声明需要storage接口
async initialize(context: IToolContext) {
// 不关心谁提供storage,只要符合IStorageService接口即可
const storage = context.getService<IStorageService>('storage');
}
}
2. 任意组合
// 组合1:MySQL + 本地卡生成器
toolManager.register(new MySQLStorageTool());
toolManager.register(new LocalCardGenerator());
// 组合2:Redis + API卡生成器
toolManager.register(new RedisStorageTool());
toolManager.register(new APICardGenerator());
// 组合3:内存存储 + 测试卡生成器(用于测试)
toolManager.register(new MemoryStorageTool());
toolManager.register(new MockCardGenerator());
3. 插件化
// 添加新功能,完全不影响现有工具
toolManager.register(new LoggerTool()); // 日志工具
toolManager.register(new MetricsTool()); // 监控工具
toolManager.register(new CacheTool()); // 缓存工具
🏗️ 在Adapter中使用
windsurf-adapter.ts
import { ToolManager } from '../../src/tools/ToolManager';
import { AccountGeneratorTool } from '../../src/tools/AccountGeneratorTool';
import { CardGeneratorTool } from '../../src/tools/CardGeneratorTool';
import { MySQLStorageTool } from '../../src/tools/MySQLStorageTool';
class WindsurfAdapter implements ISiteAdapter {
private toolManager: ToolManager;
constructor() {
this.toolManager = new ToolManager();
// 拼接需要的工具(像搭积木)
this.toolManager.register(new MySQLStorageTool());
this.toolManager.register(new AccountGeneratorTool());
this.toolManager.register(new CardGeneratorTool());
// 想要更多功能?继续注册!
// this.toolManager.register(new EmailHandlerTool());
// this.toolManager.register(new CaptchaSolverTool());
}
async initialize(context: any): Promise<void> {
// 一键初始化所有工具
await this.toolManager.initializeAll();
const toolContext = this.toolManager.getContext();
// 生成账号
if (!context.data.account?.email) {
const accountGen = toolContext.getService('account-generator');
context.data.account = await accountGen.generate();
}
}
getHandlers() {
const toolContext = this.toolManager.getContext();
return {
generateCard: async () => {
const cardGen = toolContext.getService('card-generator');
return await cardGen.generate();
},
saveToDatabase: async () => {
const storage = toolContext.getService('storage');
await storage.save('account:xxx', this.context.data.account);
}
};
}
}
✅ 对比总结
| 特性 | V1设计 | V2设计 |
|---|---|---|
| 耦合度 | 高(直接依赖) | 低(接口依赖) |
| 可替换 | 难(需改代码) | 易(改配置) |
| 测试 | 难(需mock具体类) | 易(mock接口) |
| 扩展 | 难(需修改现有代码) | 易(只需添加工具) |
| 维护 | 难(改一处影响多处) | 易(工具独立) |
🎉 这才是真正的"可拼接"!
就像:
- USB接口 - 不管是键盘、鼠标、U盘,只要符合USB规范就能插上
- 乐高积木 - 不同的积木可以自由组合
- 插座 - 不管什么电器,只要符合电压规范就能用
工具之间通过标准接口(storage、generator、validator等)通信,而不是硬编码依赖关系!