199 lines
6.5 KiB
Markdown
199 lines
6.5 KiB
Markdown
# 架构设计文档
|
||
|
||
## 核心设计原则
|
||
|
||
**分层原则:通用组件 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为什么是通用的?
|
||
|
||
```typescript
|
||
// 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特定的?
|
||
|
||
```typescript
|
||
// 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
|
||
**状态:** 已修正 ✅
|