核心域与基础设施分离
让业务核心只依赖接口(端口),数据库、消息与第三方 SDK 作为适配器实现端口:技术选型可替换,核心逻辑能脱离环境测试。依赖注入在启动或组装层完成,业务代码里不再出现直接构造基础设施的语句。
基本信息
| 结构 | 核心域依赖端口(接口),适配器实现端口 |
|---|---|
| 组装位置 | 启动层或组装模块做依赖注入 |
| 收益 | 测试可用内存适配器,不依赖真实中间件 |
| 相关原则 | 依赖倒置、单一职责 |
| 常见形态 | 端口与适配器、六边形架构 |
典型使用场景
- 需要脱离数据库跑单元测试的业务逻辑
- 第三方 SDK 隔离在适配层,不污染领域代码
- 未来可能更换存储或消息中间件的系统
- 同一业务逻辑需要多种出入口(接口、定时任务、消息)
- 沙箱与生产环境使用不同实现的场景
端口与测试替身
端口与测试替身
// 端口:核心定义接口
interface OrderRepository { Order byId(OrderId id); void save(Order order); }
// 适配器:生产用数据库,测试用内存实现
class MySqlOrderRepository implements OrderRepository { ... }
class InMemoryOrderRepository implements OrderRepository { ... }
OrderService service = new OrderService(new InMemoryOrderRepository());分层职责
| 层 | 职责 | 约束 |
|---|---|---|
| 核心域 | 业务规则与状态变化 | 不引用框架与基础设施类型 |
| 端口 | 定义核心需要的能力 | 接口面向领域语言 |
| 适配器 | 实现具体技术细节 | 只做转换与调用,不写业务分支 |
检验边界是否有效,看核心能否在没有中间件的环境里跑起来:如果单元测试必须启动数据库或消息队列,说明依赖方向还没有倒过来。
端口方法直接暴露 ORM 实体或框架类型,核心会被持久化细节渗入;更换存储实现时业务代码照样要改,隔离也就失效了。
端口应当由核心定义:接口放在业务模块里,实现放在基础设施模块;反过来让核心去实现基础设施定义的接口,依赖方向就没有真正倒过来。