假如一个对象有多个维度,就会有非常多的变体,如果增加接口的时候不克制,就会出现接口数量爆炸的情况,举个例子:
| |
这就是笛卡尔积爆炸,也叫变体爆炸。在长期维护的项目中,如果不克制地处理,这种情况很容易在不知不觉中出现,给维护带来巨大的压力。
如何处理
分层API
分层式 API 设计是很直觉的解决思路:先提供一个克制的、带有大量默认值的基础API,覆盖大多数场景;再提供一个带完整 config 结构体的扩展API,覆盖剩余场景。比如:
基础 API:
| |
完全体 API:
| |
这个模式也非常适合嵌入式环境。
完全体 API 结构体可能太复杂,我们可以提供一些预设:
| |
Builder 模式
| |
可读性强,顺序无关,IDE 自动补全方便,不过略笨重,内存敏感的时候可能会有性能压力。 主要压力来自:
- 函数调用链:每个链式 setter 都是一次调用,热点路径里会累计开销。
- 构建期临时变量:部分实现会引入临时状态或中间数据(是否发生取决于实现)。
- 代码体积增长:如果每个 setter 都独立实现,Flash/指令缓存压力会变大。
- 延迟构建的参数缓存:若采用先收集参数再
build(),保存参数需要额外内存。
先创建后配置
| |
API 扁平,可以随时增加新的 setter,但是代码行数很多,而且中间状态对象可能不合法。
小结
- 分层 API + Cfg + Preset:嵌入式最常用,便宜、可读、易扩展
- Builder:可读性最佳,代价是更多临时分配与方法调用
- 先创建后配置:扩展性最强,代价是行数多、存在中间不合法状态
核心原则只有一句:不要让维度数量决定接口数量,而要让一个接口接受多维度。