SDK 架构设计:分层、模块化与接口原则
做 SDK 开发这么多年,我踩过最大的坑就是架构设计。早期接手过一个项目,所有逻辑都摊在一个类里,业务方一接入就崩溃。说白了,SDK 这东西,它是跑在别人 App 里的代码。你的代码不干净,人家的应用就会卡死。
我习惯用 分层架构 + 模块化拆分 + 稳定接口 这套组合拳。下面聊点实实在在的体会。
1. 分层架构:把代码切三块
为什么要分层?你想想看,如果网络层和 UI 层混在一起,换个网络库就得重写半个 SDK。
我一般分成三层:
接入层(Api)—— 对外暴露的 API。
核心层(Core)—— 业务逻辑和状态管理。
基础层(Foundation)—— 网络、存储、日志。
| 层次 | 职责 | 依赖关系 |
|---|---|---|
| 接入层 | 协议校验、参数检查、回调分发 | 只依赖核心层接口 |
| 核心层 | 业务编排、状态机、调度逻辑 | 只依赖基础层接口 |
| 基础层 | DNS 解析、连接池、文件 IO | 不依赖上层 |
关键原则:依赖单向流动。下层绝不能反过来调用上层。我在项目中见过有人直接在上层回调里操作数据库,最后加了两层抽象才解耦合。
2. 模块化设计:解耦到极致
分层是纵向切,模块化是横向切。每个模块只关心一件事。
我常把 SDK 拆成下面几个模块:
- 初始化模块:配置加载、依赖检查、组件启动顺序。
- 网络模块:请求封装、重试策略、超时控制。
- 存储模块:缓存策略、数据加密、本地持久化。
- 事件总线:异步消息分发、生命周期管理。
- 日志模块:分级输出、日志回捞、性能打点。
举个代码结构例子:
sdk/
├── api/ # 接入层,对外暴露
│ ├── SdkApi.java
│ └── SdkConfig.java
├── core/ # 核心层,内部逻辑
│ ├── init/
│ │ └── InitPipeline.java
│ ├── network/
│ │ └── RequestDispatcher.java
│ └── storage/
│ └── CacheManager.java
└── foundation/ # 基础层,工具集合
├── http/
│ └── HttpClient.java
├── log/
│ └── Logger.java
└── util/
└── ThreadPoolProvider.java
我的经验:模块之间只通过接口通信。举个例子,网络模块不直接用 OkHttp,而是定义 IHttpClient 接口。这样换网络库只需加一个实现类。我曾经用这个办法让 SDK 无缝切换了三次底层网络库。
3. 接口设计原则:稳如磐石
接口就是 SDK 的契约。一旦发布,就不能随便改。我这里总结了三字诀。
3.1 稳定性 > 灵活性
尽量用 Builder 模式替代多个重载方法。参数特别多时,config.setTimeout(5000) 比 init(a,b,c,d,e) 优雅得多。我在项目中遇到过接口参数从 5 个涨到 15 个,最后不得不废弃旧接口。改成 Builder 后再也没出过这问题。
3.2 收敛暴露面
只暴露最少必要的类。内部实现类全部 包级私有 或加 @Internal 注解。业务方看到你的 API 文档只有 5 个类,心里就有底。
3.3 异步回调必须规范
所有回调回到 主线程。回调参数用 Result<T> 封装成功和失败,别让使用者去判断 null。
// 推荐的做法
public class SdkResult<T> {
private T data;
private int errorCode;
private String errorMsg;
public boolean isSuccess() { return errorCode == 0; }
public T getData() { return data; }
}
// 使用示例
sdk.fetchData(new SdkCallback<SdkResult<UserInfo>>() {
@Override
public void onResult(SdkResult<UserInfo> result) {
if (result.isSuccess()) {
// 处理成功
} else {
// 处理失败
}
}
});
3.4 版本兼容
废弃接口标注 @Deprecated,但至少保留两个大版本才移除。我不建议直接删掉方法,可以改成空实现或者抛 UnsupportedOperationException。
避坑指南:我曾经在接口里返回了 HashMap,结果业务方直接 put 了数据,导致内部共享状态全乱套。后来改成 Collections.unmodifiableMap() 才解决。
画完这张图你就明白了。左边是纵向分层,右边是横向模块。每一层都通过稳定接口与相邻层交互。模块之间彼此独立,模块内部的高内聚和模块间的低耦合做到位了,SDK 就稳了。
最后说两句
架构设计没有银弹。但分层、模块化、接口稳定这套组合拳,我用了六年,在十几个商业 SDK 里验证过。项目初期多花两天设计好骨架,后期能省两个月修 bug 的时间。这个账,一定要算清楚。