2. SDK 架构设计原则

说实话,我见过太多 SDK 因为一开始没想清楚设计原则,后面改得面目全非。开发者骂,维护的人更痛苦。今天咱们把这五个原则掰开揉碎,每个我都踩过坑,希望能帮你少走弯路。

2.1 高内聚低耦合

先说说高内聚。说白了,就是把 同类功能关在一个屋子里,别到处乱跑。比如网络请求模块,就该只管网络相关的活儿——重试、超时、证书校验。千万别在里面塞一个 UI 弹窗,或者写个本地缓存逻辑。

低耦合呢,就是模块之间通过接口说话,别直接 new 对象。

我的经验: 以前有个项目,登录 SDK 里面直接调了支付模块的类。后来支付改版,登录跟着崩。改成接口注入后,两家互不干扰。

判断标准其实很简单:能不能单独测试这个模块? 如果能,高内聚就到位了。

2.2 最小依赖

这个问题我当年栽过跟头。一个 SDK 引了十几个第三方库——Gson、OkHttp、RxJava、Guava……结果用户的应用因为依赖冲突,编译都过不了。

我的建议是:能自己写就别引入。真的需要用第三方,优先选 零依赖 的库。比如 JSON 解析,用官方的 org.json 就够了,不用非得上 Gson。

依赖原则 具体做法 避坑提示
只引入必要模块 按需导入,不打包全量 用 ProGuard/R8 做瘦身
版本统一 中央仓库声明依赖版本 别写 compileOnly 但运行时没有
避免传递依赖 用 exclude 或者 provided 我记得有一次忘记 exclude 了,用户一把辛酸泪
曾经有个教训: 依赖了某个老版本 Log 库,结果和 AndroidX 冲突,应用直接闪退。从那以后我规定了:SDK 的第三方依赖不能超过 3 个。

2.3 易扩展

你想想看,业务永远是活的。今天要加个埋点,明天要改个认证方式。SDK 如果写死了,那就等着重构吧。

我用的核心模式是 策略模式 + 工厂模式。比如推送模块,接口定义好,具体实现(极光、个推、华为)通过 SPI 或者注入加载。新厂商来了,加一个类就行,核心代码不动。

// 扩展点示例:认证器接口
public interface Authenticator {
     authenticate(Credential credential);
}
// 默认实现:密码认证
public class PasswordAuthenticator implements Authenticator { ... }
// 新需求:指纹认证,加个实现类就好
public class FingerprintAuthenticator implements Authenticator { ... }
小技巧: 预留 回调接口 给用户,比如 OnConfigChangedListener。用户可能想监听 SDK 内部的配置变化,你不提供的代价就是他 hook 你的私有方法。

2.4 API 稳定性

API 是 SDK 和用户之间的契约。改了契约,用户就要改代码。我见过被迫升级 SDK 的团队,界面重写、数据迁移,加班到半夜。

我坚持两点:公开方法加 @since 注解,标明从哪个版本开始支持;标记废弃用 @Deprecated,并且至少保留三个小版本再删。

比如一个登录方法:

// 1.x 版本
public User login(String username, String password);
// 2.0 废弃,换成了对象参数
@Deprecated
public User login(String username, String password);
public User login(LoginRequest request);

嗯,这里要注意:不要偷偷改方法签名。参数类型变了,编译不过;返回值变了,运行时崩。都是大雷。

2.5 版本兼容性设计

SDK 版本怎么升?语义化版本号(SemVer)是标准做法:主版本.次版本.补丁。但光有号不行,还得有策略。

  • 向前兼容:新版本 SDK 不能破坏旧版本 API。新增接口可以,改删不行。
  • 向后兼容:旧 SDK 数据能被新版本正确解析。常见坑是序列化对象新增字段,旧版反序列化会抛异常。解决方法是 @SerializedName 加默认值。
  • 运行时兼容:比如 Android 不同 API Level 差异。别全量判断,用 Build.VERSION.SDK_INT 分路径。
我曾经犯过的错: 升级网络框架,把 OkHttp 3 换成 4,觉得接口差不多,直接改依赖。结果用户用的 SSL 库不兼容,线上大片网络故障。后来强制要求:主版本升级必须跑完整回归 + 兼容测试。

这里画张图,把这五个原则的关系串起来。

SDK 架构设计五大原则关系图 SDK 架构 高内聚低耦合 最小依赖 易扩展 API 稳定性 版本兼容性 五大原则相互支撑 缺一不可

这五个原则其实层层递进。先保证内聚耦合,再控制依赖,接着预留扩展点,然后守住 API 稳定,最后用版本兼容性兜底。顺序别搞反了,否则后面会很难受。

我的习惯: 每做一个新模块,先对着这五个原则打个分。哪项不到 7 分就不合。一开始严格要求,后面省心十倍。