2. 架构设计原则与模式

做SDK集成,说白了就是在别人的地盘上跳舞。你的代码要进入宿主App的进程空间,跟人家的主线程、内存管理、网络栈朝夕相处。这里头稍微犯点错,轻则功能异常,重则整App闪退。

我个人习惯,在动手写第一行代码之前,先把几个核心设计原则刻在脑子里。这些原则不是理论空谈,它们能直接帮你避开线上事故。

2.1 四大核心设计原则

我总结了四个必须遵守的原则,这也是我在十几个商业级SDK项目里踩坑踩出来的。

原则 核心思想 我吃过的亏
高内聚低耦合 SDK内部逻辑自成一体,对外暴露最小接口 曾经把所有工具类扔到一个模块,改一个地方全盘重编
接口隔离 宿主调用方不用依赖它不需要的方法 早期我设计了一堆万能初始化接口,结果没人用得了
依赖倒置 高层模块不依赖低层实现,双方依赖抽象 硬编码网络库,换一个库要改半个SDK
开闭原则 对扩展开放,对修改封闭 加一个新渠道要改核心类,上线前总是提心吊胆

核心要点:这些原则不是摆设。你在设计SDK模块边界时,每多一份对外暴露,就多一份维护负担。能私有的就别公开,能抽象的别写死。

2.2 分层架构设计

分层是SDK最经典的架构模式。我参与的几乎每个项目都采用了类似的分层方式,只是层数多少、粒度粗细的区别。

为什么一定要分层?你想想看,如果所有代码搅在一起,接口层、业务层、底层实现全部揉成一个胖模块。改一个底层缓存策略,结果接口层的返回格式变了,宿主编译直接报错。这是典型的耦合灾难。

我推荐的三层结构:

  1. 接口层(API Layer) — 对宿主暴露的门面。稳定、简洁、版本化。
  2. 业务层(Business Layer) — 核心逻辑编排。调用底层能力,组合成业务功能。
  3. 基础层(Foundation Layer) — 网络、存储、线程、日志等基础设施。

我在某金融服务SDK里遇到过一件事。业务层直接依赖了一个第三方网络库的某个类。后来对方升级了库,改了类名。全线编译失败。这就是依赖方向反了。正确做法是:业务层依赖接口层定义的抽象,基础层去实现这个抽象。

实用技巧:接口层的每个公开方法,都应该能独立测试。如果某个方法需要事先调用三个其他方法才能用,说明接口设计有问题。我习惯用"宿主视角"写接口:只写调用方真正需要的,不多不少。

2.3 插件化架构模式

插件化不是游戏SDK的专利。我最近几年做的大中型SDK,基本都采用了插件化思路。核心SDK保持轻量,各种扩展能力以插件形式动态加载。

为什么?因为宿主App有包体积限制、有合规审核、有动态升级需求。把所有功能都打进一个aar里,既不现实,也不专业。

插件化架构的几个关键要素:

  • SPI机制(Service Provider Interface)— 定义插件接口,运行时通过反射或注册表发现实现。
  • 生命周期管理 — 插件的加载、初始化、销毁必须由主SDK统一管控。
  • 失败隔离 — 某个插件崩溃,不能拖垮主SDK,更不能让宿主App闪退。

我记得有一次在支付SDK中集成人脸识别插件。那个插件初始化时要加载几百兆的模型文件。如果在主线程加载,宿主App直接ANR。后来我们在插件加载器里加了线程切换和超时保护。嗯,这就是架构设计带来的工程价值。

避坑指南:我曾经见过某个SDK的插件化方案,插件之间居然能直接调用对方的内部类。这完全违背了隔离初衷。插件之间只能通过SPI接口通信,任何直接引用都应该视为架构腐化。

2.4 模块化与组件化

模块化是按功能边界拆包,组件化是按可复用粒度拆包。两者不冲突,但你要先搞清楚自己的场景。

我一般这样区分:

维度 模块化 组件化
目的 降低耦合、分离关注点 提高复用、独立演进
粒度 偏大(登录、支付、推送) 偏小(网络库、图片加载、日志)
依赖关系 单向依赖,禁止循环引用 可被多个上层模块依赖
版本管理 统一版本号 独立版本号 + 兼容契约

说白了,模块化解决的是"不要搅成一锅粥",组件化解决的是"这块代码能不能拿给下一个项目用"。我建议新手先从模块化入手,等你的SDK规模膨胀到一定程度,再拆组件。别一开始就过度设计。

2.5 架构设计的核心逻辑图

下面这张图,是我在做架构设计时经常画给团队看的。它把分层、模块、插件整合到一个视图中,反映了SDK内部的核心流动方向。

SDK架构设计核心逻辑图 接口层 (API Layer) 公开接口 · 版本契约 · 门面模式 业务层 (Business Layer) 逻辑编排 · 状态管理 · 策略调度 登录模块 支付模块 推送模块 分享模块 基础层 (Foundation Layer) 抽象接口 · 具体实现 · 基础设施 网络库实现 OkHttp / Retrofit 存储实现 Room / MMKV 线程管理 协程 / 线程池 插件 SPI 依赖抽象 依赖抽象 核心约束 分层之间只通过抽象接口通信 · 模块内高内聚 · 模块间低耦合 · 插件隔离

你看,这张图展示了三个层次之间的依赖方向。接口层依赖业务层的抽象。业务层依赖基础层的抽象。基础层提供具体实现。箭头方向就是依赖方向。这刚好体现了依赖倒置原则——高层不直接依赖低层的细节。

2.6 架构设计的持续进化

没有一劳永逸的架构设计。我做过的几个SDK,几乎每年都要做一次架构盘点。为什么?因为业务在变,宿主环境在变,第三方依赖在变。

我一般用这几条标准来判断架构是否需要调整:

  • 加一个新功能,需要改动三个以上模块吗?
  • 升级一个依赖库,编译错误超过5处吗?
  • 单元测试覆盖率低于40%吗?
  • 新人接手,需要一周以上才能看懂调用链路吗?

如果任意一条命中,说明架构出现腐化信号。该重构就重构,别等到线上出事故再动手。

我的习惯:每次迭代都留20%的工时给架构优化。不是大改,而是持续的小重构。比如今天抽一个接口,明天解一个循环依赖。这样做,架构不会突然崩塌。

总结一句话:架构设计的本质,是管理复杂度。分层、模块化、插件化、接口隔离——所有这些模式,最终目的都是让你的SDK在宿主App里能稳定、高效、优雅地运行。嗯,想清楚这一点,设计原则就不再是死记硬背的知识点,而是你手里的工程工具。