分层架构的一个重要原则是:每层只能与位于其下方的层发生耦合。
分层架构分两种:一种是严格分层架构,规定某层只能与直接位于其下方的层发生耦合;另一种是松散分层架构,允许任意上方层与任意下方层发生耦合。
下图是一个典型的DDD传统分层架构。
以上分层架构中各层都有自己的职责:
用户接口层负责处理用户请求和用户显示;
应用层实现不同业务场景下的用例或业务流程。其中应用服务通常接收来自用户接口层的请求,然后通过资源库获取聚合实例,最后执行相应的命令操作,如下示例:
// 应用层的用例
public void cancelOrder(Long orderId) {
Order order = orderRepository.findById(orderId);
// 领域层的业务逻辑
order.cancel()
orderRepository.save(order);
}
领域层实现系统的核心业务逻辑,主要包含基于DDD业务建模产生的领域模型,这里的业务逻辑不同于应用层中的业务流程,如上代码示例;
基础设施层为其它各层提供通用的技术和基础服务,比如数据持久化功能。
DDD中资源库(Repository)用来获取或持久化聚合,每个聚合都拥有一个对应的资源库。由此可见资源库应该和聚合位于同一层,资源库接口定义应该位于领域层,而资源库接口实现需要依赖基础设施层的持久化机制,此时资源库接口实现放在哪一层对传统分层架构来说是个问题。
如果把资源库接口实现放在基础设施层,那么基础设施层就会向上依赖领域层,这样就违反了分层架构的原则:每层只能与位于其下方的层发生耦合。
或者可以放在领域层,但是这样会使领域层依赖数据持久化的实现细节,导致领域层不再是一个稳定层。
也可以放在应用层,不过和放在领域层会有同样的问题。
那有没有更好的方式呢?
有,采用依赖倒置,打破分层架构原则。
依赖倒置(或依赖反转)原则(Dependency inversion principle,DIP),由Bob大叔提出,其定义如下: