# Adapter 重要决策记录

**版本：** 3.0  
**最后更新**: 2026-01-17

---

**注意**：本模块**尚未实现**，以下为概念设计阶段的决策记录。

---

本文档记录了 Adapter 模块的重要架构设计决策，包括问题背景、可选方案、决策理由和影响。

---

## 决策 1：分层设计（Core + Userspace）

**日期**：2026-01-17  
**状态**：概念设计

### 痛点

如果所有功能都在一个地方，会导致：
- 职责不清：数据准备和业务处理混在一起
- 难以扩展：用户无法自由创建、修改 action
- 耦合度高：用户代码与核心代码耦合

### 可选方案

**方案 A：所有功能都在核心代码中**
- 优点：实现简单，所有代码集中管理
- 缺点：核心代码与用户代码耦合，难以扩展

**方案 B：分层设计（Core + Userspace）** ✅
- 优点：职责清晰，便于扩展，解耦
- 缺点：需要设计接口和加载机制

### 为什么选择当前方案

选择方案 B 的理由：
1. **职责清晰**：Core 模块负责数据准备（批量查找模拟结果），Userspace 模块负责业务处理（用户自定义 action）
2. **便于扩展**：用户可以自由创建、修改 action，无需修改核心代码
3. **解耦**：Core 模块和 Userspace 模块通过统一接口连接，保持解耦

### 影响

- Core 模块（`core/modules/adapter/`）负责批量查找模拟结果，将数据传递给 action
- Userspace 模块（`userspace/adapters/`）存放用户自定义的 action
- 通过动态导入机制（`importlib.import_module`）加载 action
- 核心代码不依赖用户空间的 action，保持解耦

---

## 决策 2：基类 + 继承设计

**日期**：2025-12-19  
**状态**：已实施

### 痛点

如果直接使用函数或回调，会导致：
- 接口不统一：不同 adapter 的实现方式可能不一致
- 功能重复：每个 adapter 都需要实现配置加载、日志等功能
- 难以验证：无法在编译时检查 adapter 是否实现了必要的方法

### 可选方案

**方案 A：使用函数或回调**
- 优点：实现简单，无需继承
- 缺点：接口不统一，功能重复，难以验证

**方案 B：使用基类 + 继承** ✅
- 优点：接口统一，功能复用，易于验证
- 缺点：需要定义基类

### 为什么选择当前方案

选择方案 B 的理由：
1. **接口统一**：通过 `BaseOpportunityAdapter` 基类定义统一的接口（`process` 方法）
2. **功能复用**：基类提供通用功能（配置加载、日志等），用户无需重复实现
3. **易于验证**：可以通过 `isinstance` 检查 adapter 是否继承基类
4. **类型安全**：通过抽象方法，确保用户必须实现 `process` 方法

### 影响

- 所有 adapter 必须继承 `BaseOpportunityAdapter`
- 用户只需实现 `process` 方法，其他功能由基类提供
- 通过 `AdapterValidator` 可以验证 adapter 是否符合规范

---

## 决策 3：支持多个 Adapter

**日期**：2025-12-19  
**状态**：已实施

### 痛点

如果只支持单个 adapter，会导致：
- 功能受限：同一批机会只能输出到一个目标
- 使用不便：如果需要同时输出到控制台和 Webhook，需要创建复合 adapter

### 可选方案

**方案 A：只支持单个 adapter**
- 优点：实现简单，逻辑清晰
- 缺点：功能受限，使用不便

**方案 B：支持多个 adapter** ✅
- 优点：功能灵活，可以同时输出到多个目标
- 缺点：需要处理 adapter 失败的情况

### 为什么选择当前方案

选择方案 B 的理由：
1. **功能灵活**：同一批机会可以同时输出到多个目标（控制台、Webhook、文件等）
2. **使用方便**：用户可以在配置中指定多个 adapter，无需创建复合 adapter
3. **容错性**：如果某个 adapter 失败，不影响其他 adapter

### 影响

- Scanner settings 中支持配置多个 adapter（`adapter_names: ["console", "webhook"]`）
- `AdapterDispatcher` 依次调用每个 adapter
- 如果某个 adapter 失败，记录错误并继续处理其他 adapter

---

## 决策 4：配置驱动设计

**日期**：2025-12-19  
**状态**：已实施

### 痛点

如果配置硬编码在 adapter 中，会导致：
- 灵活性差：每次修改配置都需要修改代码
- 难以复用：同一个 adapter 无法在不同场景下使用不同配置
- 维护困难：配置与代码混在一起，难以管理

### 可选方案

**方案 A：配置硬编码在 adapter 中**
- 优点：实现简单，无需配置文件
- 缺点：灵活性差，难以复用

**方案 B：配置驱动（每个 adapter 有自己的 settings.py）** ✅
- 优点：配置与代码分离，灵活性高，易于复用
- 缺点：需要配置文件管理机制

### 为什么选择当前方案

选择方案 B 的理由：
1. **配置与代码分离**：配置放在 `settings.py` 中，与代码分离，便于管理
2. **灵活性高**：可以轻松修改配置，无需修改代码
3. **易于复用**：同一个 adapter 可以在不同场景下使用不同配置
4. **支持嵌套配置**：通过点号分隔的 key（如 `"output.format"`）支持嵌套配置

### 影响

- 每个 adapter 可以有自己的配置文件（`userspace/adapters/{adapter_name}/settings.py`）
- 基类自动加载配置，用户通过 `get_config` 方法访问
- 配置缺失时使用默认值，保证容错性

---

## 决策 5：提供 HistoryLoader 工具

**日期**：2025-12-19  
**状态**：已实施

### 痛点

如果 adapter 需要展示历史统计，会导致：
- 代码重复：每个 adapter 都需要实现历史加载逻辑
- 耦合度高：adapter 需要了解 PriceFactorSimulator 的结果结构
- 维护困难：如果结果结构变化，需要修改所有 adapter

### 可选方案

**方案 A：每个 adapter 自己实现历史加载**
- 优点：实现简单，无需额外工具
- 缺点：代码重复，耦合度高，维护困难

**方案 B：提供 HistoryLoader 工具类** ✅
- 优点：代码复用，解耦，易于维护
- 缺点：需要实现工具类

### 为什么选择当前方案

选择方案 B 的理由：
1. **代码复用**：通过 `HistoryLoader` 工具类，所有 adapter 可以复用历史加载逻辑
2. **解耦**：adapter 不需要了解 PriceFactorSimulator 的结果结构，只需调用 `HistoryLoader`
3. **易于维护**：如果结果结构变化，只需修改 `HistoryLoader`，不影响 adapter

### 影响

- 提供 `HistoryLoader` 工具类，封装历史加载逻辑
- Adapter 可以通过 `HistoryLoader.load_stock_history()` 加载历史统计
- 如果历史数据不存在，返回 `None`，adapter 可以优雅处理

---

## 决策 6：容错设计（默认输出）

**日期**：2025-12-19  
**状态**：已实施

### 痛点

如果所有 adapter 都失败，会导致：
- 用户看不到结果：扫描完成但没有输出，用户体验差
- 难以调试：不知道是 adapter 失败还是扫描没有发现机会

### 可选方案

**方案 A：如果所有 adapter 失败，不输出任何内容**
- 优点：实现简单
- 缺点：用户体验差，难以调试

**方案 B：如果所有 adapter 失败，使用默认输出** ✅
- 优点：保证用户能看到结果，便于调试
- 缺点：需要实现默认输出方法

### 为什么选择当前方案

选择方案 B 的理由：
1. **保证输出**：即使所有 adapter 都失败，用户也能看到扫描结果
2. **便于调试**：默认输出可以帮助用户判断是 adapter 失败还是扫描没有发现机会
3. **用户体验**：确保用户始终能看到扫描结果，不会因为 adapter 失败而丢失信息

### 影响

- `BaseOpportunityAdapter` 提供 `default_output` 静态方法
- 如果所有 adapter 都失败，`AdapterDispatcher` 会调用 `default_output`
- 默认输出提供基本的扫描结果信息（日期、策略名、机会数、机会列表）

---

## 相关文档

- **[overview.md](./overview.md)**：模块概览
- **[architecture.md](./architecture.md)**：架构文档

> **提示**：本文档记录了 Adapter 的重要设计决策。如需了解完整的架构设计，请参考 [architecture.md](./architecture.md)。

---

**文档结束**
