auto-account-machine/browser-automation-ts/TOOL-V2-DESIGN.md
2025-11-21 17:59:49 +08:00

6.1 KiB
Raw Permalink Blame History

Tool V2 - 可拼接式设计

🎯 设计理念

核心原则

  1. 松耦合 - 工具之间通过接口通信,不直接依赖
  2. 可替换 - 任何工具都可以被同类工具替换
  3. 可组合 - 像乐高一样自由组合
  4. 依赖注入 - 通过服务名获取依赖,而非硬编码

📦 架构示意图

┌─────────────────────────────────────────┐
│          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. 任意组合

// 组合1MySQL + 本地卡生成器
toolManager.register(new MySQLStorageTool());
toolManager.register(new LocalCardGenerator());

// 组合2Redis + 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等通信而不是硬编码依赖关系