6.5 KiB
6.5 KiB
架构设计文档
核心设计原则
分层原则:通用组件 vs Provider特定组件
📐 架构图
┌─────────────────────────────────────────┐
│ 通用层 (Universal Layer) │
│ 不调用浏览器特定API,所有Provider共享 │
├─────────────────────────────────────────┤
│ - WorkflowEngine │
│ - 接口定义 (IAction, ISmartSelector) │
│ - 类型定义 (Types) │
│ - 抽象基类 (BaseAction, BaseProvider) │
└──────────────┬──────────────────────────┘
│
↓ 依赖接口
┌─────────────────────────────────────────┐
│ Provider特定层 (Provider Layer) │
│ 调用浏览器特定API,每个Provider独立实现 │
├─────────────────────────────────────────┤
│ - Actions (click, input, etc.) │
│ - SmartSelector │
│ - ActionFactory │
│ - BrowserProvider │
└─────────────────────────────────────────┘
🗂️ 目录结构
src/
├── core/ # 通用核心层 ✅
│ ├── interfaces/ # 接口定义
│ │ ├── IBrowserProvider.ts # Provider接口
│ │ ├── IAction.ts # Action接口
│ │ └── ISmartSelector.ts # SmartSelector接口
│ ├── base/ # 抽象基类
│ │ ├── BaseBrowserProvider.ts
│ │ └── BaseAction.ts
│ └── types/ # 类型定义
│ └── index.ts
│
├── workflow/ # 通用工作流 ✅
│ └── WorkflowEngine.ts # 工作流引擎(通用!)
│
├── factory/ # 工厂模式 ✅
│ └── BrowserFactory.ts
│
└── providers/ # Provider实现层 ❌
├── adspower/ # AdsPower (Puppeteer)
│ ├── AdsPowerProvider.ts # Provider实现
│ ├── actions/ # AdsPower专用Actions
│ │ ├── ClickAction.ts
│ │ ├── InputAction.ts
│ │ └── ...
│ └── core/ # AdsPower专用Core
│ ├── SmartSelector.ts # Puppeteer实现
│ └── ActionFactory.ts
│
└── playwright/ # Playwright (未来)
├── PlaywrightProvider.ts
├── actions/ # Playwright专用Actions
└── core/
├── SmartSelector.ts # Playwright实现
└── ActionFactory.ts
📊 组件分类
✅ 通用组件(所有Provider共享)
| 组件 | 位置 | 职责 |
|---|---|---|
| WorkflowEngine | workflow/ |
执行工作流,调用Action接口 |
| 接口定义 | core/interfaces/ |
定义规范(IAction, ISmartSelector等) |
| 类型定义 | core/types/ |
配置、结果等类型 |
| 抽象基类 | core/base/ |
通用实现逻辑 |
| BrowserFactory | factory/ |
创建Provider实例 |
特点:
- ✅ 不调用浏览器特定API
- ✅ 只依赖接口,不依赖实现
- ✅ 所有Provider可以共享代码
❌ Provider特定组件
| 组件 | 位置 | 职责 | 原因 |
|---|---|---|---|
| Actions | providers/*/actions/ |
执行具体操作 | 需要调用page.click()等API |
| SmartSelector | providers/*/core/ |
查找元素 | 需要调用page.waitForSelector()等 |
| ActionFactory | providers/*/core/ |
创建Action实例 | 返回Provider特定的Action类 |
| Provider | providers/*/ |
管理浏览器 | 调用Puppeteer/Playwright等API |
特点:
- ❌ 调用浏览器特定API
- ❌ 每个Provider独立实现
- ❌ 不能跨Provider共享
💡 为什么这样设计?
WorkflowEngine为什么是通用的?
// WorkflowEngine只调用接口,不依赖具体实现
class WorkflowEngine {
async executeStep(step) {
// 从Factory获取Action(多态)
const ActionClass = this.actionFactory.getAction(step.action);
const action = new ActionClass(step, this.context);
// 执行(通过接口调用,不关心Puppeteer还是Playwright)
await action.execute();
}
}
关键: 只依赖IAction接口,不知道是PuppeteerClickAction还是PlaywrightClickAction!
SmartSelector为什么是Provider特定的?
// Puppeteer版本
class PuppeteerSmartSelector {
async find(timeout) {
return await this.page.waitForSelector(selector, { timeout });
// ↑ Puppeteer特定API
}
}
// Playwright版本(API不同!)
class PlaywrightSmartSelector {
async find(timeout) {
return await this.page.locator(selector).waitFor({ timeout });
// ↑ Playwright特定API
}
}
关键: 必须直接调用浏览器API,无法抽象!
🔄 工作流程
1. 用户创建Provider
↓
BrowserFactory.create('adspower')
2. WorkflowEngine执行
↓
new WorkflowEngine(workflow, context, actionFactory)
3. 执行每个步骤
↓
actionFactory.getAction('click') // 获取AdsPower的ClickAction
↓
action.execute() // 调用Puppeteer API
关键: WorkflowEngine不知道也不关心是哪个Provider!
✅ 总结
| 层次 | 组件 | 通用/特定 | 原因 |
|---|---|---|---|
| 业务层 | WorkflowEngine | ✅ 通用 | 只调用接口 |
| 接口层 | IAction, ISmartSelector | ✅ 通用 | 定义规范 |
| 实现层 | Actions, SmartSelector | ❌ Provider特定 | 调用浏览器API |
| 基础层 | Provider | ❌ Provider特定 | 管理浏览器 |
设计原则:
- 依赖倒置:上层依赖接口,不依赖实现
- 开闭原则:添加新Provider不修改通用层
- 单一职责:通用层负责流程,Provider层负责实现
创建时间: 2025-11-21
状态: 已修正 ✅