Adapter 模式
将一个类的接口转换成调用方期望的另一种接口,使原本因接口不兼容而无法协作的类可以协同工作。接口必须发生变化——这是与 Proxy(接口不变)和 Decorator(接口不变)的核心区分标准。
定义
Adapter 模式(适配器模式)将一个接口翻译成另一种接口。调用方只知道目标接口,Adapter 在内部把调用转换成被适配对象能理解的格式。
区分标准:接口是否发生变化。
| 模式 | 接口变化 | 是否委托原对象 | 核心用途 |
|---|---|---|---|
| Adapter | ✅ 有(源接口 → 目标接口) | ❌ 不委托,只做数据转换 | 格式/协议翻译 |
| Proxy | ❌ 无(同接口) | ✅ 透传或拦截后透传 | 版本兼容、访问控制 |
| Decorator | ❌ 无(同接口) | ✅ 持有引用,增强行为 | 横切关注点叠加 |
Proxy 和 Decorator 都"包装"原对象且接口不变;Adapter 做接口翻译,不委托原对象的方法。
vercel/ai 中的典型案例
案例一:convertToOpenAIChatMessages(单函数 Adapter)
// openai-chat-language-model.ts:L129
function convertToOpenAIChatMessages(
prompt: LanguageModelV4Prompt // 输入:标准接口格式
): OpenAIChatPrompt { // 输出:OpenAI API 专有格式
// 纯数据转换,不委托任何对象的方法
}
输入是 vercel/ai 标准的 prompt 结构(LanguageModelV4Prompt),输出是 OpenAI Chat Completions API 能接受的 JSON 格式(OpenAIChatPrompt)。这是一个纯函数 Adapter——没有包装对象,只有格式转换。
案例二:OpenAI 四套 Provider 实现(类 Adapter)
| 实现类 | 源接口(OpenAI API) | 目标接口 |
|---|---|---|
OpenAIChatLanguageModel | Chat Completions API | LanguageModelV4 |
OpenAICompletionLanguageModel | Legacy Completions API | LanguageModelV4 |
OpenAIResponsesLanguageModel | Responses API | LanguageModelV4 |
OpenAIRealtimeModel | Realtime API | LanguageModelV4 |
四套实现是Multiple Adapters for One Target Interface——同一个 LanguageModelV4 目标接口,四种 OpenAI API 路径各有一个 Adapter 实现。极薄接口(只有 doGenerate + doStream 两个方法)让这四个 Adapter 的实现成本极低;若目标接口有 10 个方法,实现成本会是现在的 5 倍。
变体注意:V2→V3 的重量 Proxy 是"Proxy 包装 Adapter 逻辑"
as-language-model-v3.ts 用 JavaScript Proxy 语法,但在拦截的 doGenerate 里做了 Adapter 语义的数据转换(usage 结构重构)。选 Proxy 而不是纯 Adapter 是工程原因:Proxy 能"有的属性拦截转换,其余全透传",纯 Adapter 要实现所有方法。这是模式的变体,不是标准 Adapter,也不是标准 Proxy。
关联知识
- [[proxy]] — 接口不变的包装模式,与 Adapter 的核心区别在于接口是否变化
- [[namespace-extension]] — 另一种扩展策略,不改变接口而是预留扩展槽