开发手记 · 第 6 / 11 篇 合集目录 ‹ 上一篇 下一篇 ›

翻这套工业数据 WebApi 的源码时,最让我佩服的一处,是它真的做到了"一套业务代码,伺候三种库房"。

客户用的数据库不一样:有的是 SQL Server,有的是 PostgreSQL,还有一批在换自主可控的某国产数据库。三种库的方言、分页、导出写法都不通。早年间这种差异会一路漏到业务层,加一家库就改一片代码。但我翻到数据访问那一层,发现他们把差异关进了一个可替换的 provider 笼子里。

(等价改写,名字换掉了)

// 图纸:业务只说"存/取",方言一字不写
public interface IRepository { void Save(Row r); Row[] Load(string k); }
// 三库各自照图施工,方言消化在自己那间
public class SqlServerRepo : IRepository { /* ... */ }
public class PostgresRepo  : IRepository { /* ... */ }
public class DomesticRepo  : IRepository { /* 某国产库的写法 */ }

业务层只认这张图纸,不认具体哪家库。要加一种新库房,就新建一个实现、挂上登记,业务一行不动。我在代码里数到 RepositoryProvider 这一层被引用了 94 处——全仓这么多数据访问点,全被这个抽象稳稳接住,没有一处把方言漏上来。

更让我意外的是,三种库不是谁取代谁,而是长期并存:老客户还在 SQL Server 上,新项目往 PostgreSQL 迁,信创要求的那批落在国产库。一个抽象同时兜住三代库房,业务代码一行都不用感知底下换没换。

我后来才看清,这笼子就是把依赖倒置落了地。es04 那篇讲过"适配三种库"的代价,这篇要补的半句是正面的:代价管不管得住,就看笼子关得死不死。关死了,加一家库就像给商场加个摊位;关不死,差异满地跑,加一家就得改全网。

现在回头看,把差异关进底层一个可替换的笼子,是这个平台能长期长胖、又不被方言拖垮的根本原因之一。我后来带新人看这层,第一句总是:别去记哪家库长什么样,记住这张图纸就行——一个抽象把"数据库的差异"和"业务的脑力"隔开了,这才是它最值钱的地方。