文章目录
- 一、问题
- 二、先解决第一个问题:接口不统一(Adapter)
- [三、第二个问题:Adapter 多了,用哪个?(Strategy)](#三、第二个问题:Adapter 多了,用哪个?(Strategy))
- [四、把"选择逻辑"集中管理(Strategy Router)](#四、把“选择逻辑”集中管理(Strategy Router))
- 五、最终调用方式
- 六、这种组合在哪些业务场景特别常见?
- [七、更多的源码:Spring Cache:如何把 Redis / Caffeine / Ehcache 适配成同一套 Cache API](#七、更多的源码:Spring Cache:如何把 Redis / Caffeine / Ehcache 适配成同一套 Cache API)
一、问题
当一个系统需要同时接入多个第三方 SDK,而这些 SDK:
能力相似(功能重合)
接口不一致(方法、参数、返回值都不同)
未来还可能继续扩展
如果在业务层直接使用它们,代码通常会变成这样
java
if (type == A) {
// 调 A 的 SDK
} else if (type == B) {
// 调 B 的 SDK
}
这是一种糟糕的处理方法,每次随着新增一种SDK 都需要去调整对应的if else 代码 导致大量的嵌套循环。
本文将以实际的例子 去讲解 如何使用适配器模式+ 策略者模式
去优化如此冗长的代码。
将以spring ai 引入 aiyun dashScope 的SDK
以及 引入 openAi SDK为例子 去讲解。
二、先解决第一个问题:接口不统一(Adapter)
目标
让业务层只面对一种"能力接口",而不是多个 SDK。
做法
定义一个统一的适配器接口,抽象出业务真正关心的能力:
java
public interface AIModelAdapter {
String getModelId();
boolean isEnabled();
String chat(List<Map<String, String>> messages);
Flux<String> stream(List<Map<String, String>> messages);
float[] embed(String text);
}
各个 SDK 各自实现适配器
java
public class AliyunAdapter implements AIModelAdapter {
@Override
public String chat(...) {
// 阿里云 SDK 调用细节
}
}
java
public class OpenAIAdapter implements AIModelAdapter {
@Override
public String chat(...) {
// OpenAI SDK 调用细节
}
}
最终实现:
屏蔽 SDK 差异
统一调用方式
新增 SDK 只需新增 Adapter
业务代码不再直接依赖第三方库
三、第二个问题:Adapter 多了,用哪个?(Strategy)
Adapter 解决了"怎么用 SDK",但没解决"用哪一个"。
如果继续在业务层写判断:
java
if (modelId.equals("aliyun")) {
return aliyunAdapter;
}
本质上还是 if-else,只是换了个地方。
四、把"选择逻辑"集中管理(Strategy Router)
核心原则
选择逻辑必须集中,不能散落在业务代码中。
策略仓库:集中管理所有 Adapter
java
public class ModelRegistry {
private final Map<String, AIModelAdapter> adapters = new HashMap<>();
public Optional<AIModelAdapter> get(String modelId) {
return Optional.ofNullable(adapters.get(modelId));
}
/**
* 注册模型适配器
*/
public void register(AIModelAdapter adapter) {
adapters.put(adapter.getModelId(), adapter);
log.info("Registered AI model adapter: {} ({}), enabled: {}",
adapter.getModelName(), adapter.getModelId(), adapter.isEnabled());
}
}
策略路由器:只负责"选哪一个"
java
public class ModelRouter {
ModelRegistry
public AIModelAdapter route(Long userId) {
// ModelRegistry.get()
// 根据user的选择 从 ModelRegistry 的map中返回可用的模型 adapter
return selectedAdapter;
}
}
五、最终调用方式
业务层最终只剩下这两行:
java
AIModelAdapter adapter = modelRouter.route(userId);
adapter.chat(messages);
六、这种组合在哪些业务场景特别常见?
支付渠道(支付宝 / 微信 / 银联)
短信服务(多云厂商)
对象存储(OSS / S3 / MinIO)
风控规则 / 排序策略
AI 模型 / 算法切换
只要你看到:
"可能还会再接一家"
"需要按条件选择实现"
这套结构几乎一定用得上。
七、更多的源码:Spring Cache:如何把 Redis / Caffeine / Ehcache 适配成同一套 Cache API
适配器接口:org.springframework.cache.Cache
这是真正的核心接口(简化后):
java
public interface Cache {
String getName();
Object getNativeCache();
ValueWrapper get(Object key);
void put(Object key, Object value);
void evict(Object key);
void clear();
}
具体适配器:Redis / Caffeine / Ehcache
Redis 的适配器(简化结构)
java
public class RedisCache implements Cache {
private final RedisOperations redisOperations;
@Override
public ValueWrapper get(Object key) {
Object value = redisOperations.opsForValue().get(key);
return (value != null ? () -> value : null);
}
@Override
public void put(Object key, Object value) {
redisOperations.opsForValue().set(key, value);
}
}
Caffeine 的适配器(简化)
java
public class CaffeineCache implements Cache {
private final com.github.benmanes.caffeine.cache.Cache<Object, Object> cache;
@Override
public ValueWrapper get(Object key) {
Object value = cache.getIfPresent(key);
return (value != null ? () -> value : null);
}
@Override
public void put(Object key, Object value) {
cache.put(key, value);
}
}
你可以清楚看到:
Redis 用的是 RedisOperations
Caffeine 用的是 cache.getIfPresent
但对外暴露的永远是 Cache 接口