按功能打包时如何解除核心领域模块与重型依赖的绑定?
问题澄清:你对DDD/按功能打包的理解偏差
你当前的困境不是按功能打包或DDD的固有矛盾,而是错误地将核心领域模型与基础设施代码耦合在同一个模块,导致依赖被不必要地传递。按功能打包的核心是按业务边界组织代码,但绝不是把某业务下的所有代码(包括领域、仓储、API适配)塞进同一个模块;DDD更是强调核心领域层的纯净性——核心领域模型必须是无外部依赖的纯业务逻辑载体。
核心解决方案:模块拆分+依赖倒置
1. 抽离纯净的核心领域模块
单独创建vehicle-domain模块,只存放纯领域相关代码:
- 领域对象:
Vehicle实体、相关值对象(比如VehicleId、LicensePlate) - 领域服务:仅处理纯业务逻辑的服务(比如
VehicleStatusValidator,只做车辆状态合规校验,不碰数据库或HTTP) - 领域抽象:
VehicleRepository接口、领域事件定义 - 这个模块不能引入任何外部依赖(SQL库、HTTP库都不行),是所有其他模块可以安全依赖的“纯净核心”。
2. 拆分基础设施与适配模块
把带外部依赖的代码拆分到独立模块:
vehicle-infrastructure:存放VehicleRepository的SQL实现、VehicleQueries的具体查询逻辑,这里才引入SQLLibrary-1.0vehicle-api-adapter:如果有HTTP相关的适配逻辑(比如车辆数据的REST接口),单独放在这个模块,引入HttpLibrary-1.0- 这些模块只能依赖
vehicle-domain模块,遵循DDD的依赖倒置原则:高层领域模块不依赖低层基础设施,两者都依赖领域层的抽象接口。
3. 精准控制依赖传递
- 当
Advertisements项目只需要Vehicle领域对象时,仅依赖vehicle-domain模块,完全不会带入SQL/HTTP库 - 只有需要使用仓储查询、HTTP交互的服务(比如车辆管理核心服务),才同时依赖
vehicle-domain和对应的基础设施模块
实际项目落地细节(Scala/Java通用)
用Maven/Gradle多模块项目实现分层:
myservice/ ├── vehicle-domain/ # 纯领域模型,无外部依赖 ├── vehicle-infrastructure/ # SQL仓储实现,依赖vehicle-domain + SQLLibrary ├── vehicle-api-adapter/ # HTTP接口适配,依赖vehicle-domain + HttpLibrary └── advertisements/ # 仅依赖vehicle-domain
- 领域层的抽象接口:在
vehicle-domain里定义VehicleRepository接口,vehicle-infrastructure里写具体的SQL实现,这样领域层完全不绑定任何持久化技术 - 避免领域服务污染:领域服务只处理业务规则,比如判断车辆是否可出租,不直接操作数据库或调用外部API,而是通过注入
VehicleRepository接口来完成数据操作
总结
你的问题本质是分层不足导致的依赖泄露,而非架构方式的固有缺陷。通过拆分核心领域与基础设施模块,严格遵循依赖倒置,既能保留按功能打包的业务聚合优势,又能实现领域模型的安全复用,彻底避免不必要的依赖传递和二进制兼容问题。
内容的提问来源于stack exchange,提问作者Hunor Kovács
相关产品推荐
相关产品推荐

