一、传统分层架构

分层架构的一个重要原则是:每层只能与位于其下方的层发生耦合。

分层架构分两种:一种是严格分层架构,规定某层只能与直接位于其下方的层发生耦合;另一种是松散分层架构,允许任意上方层与任意下方层发生耦合。

下图是一个典型的DDD传统分层架构。

以上分层架构中各层都有自己的职责:

用户接口层负责处理用户请求和用户显示;

应用层实现不同业务场景下的用例或业务流程。其中应用服务通常接收来自用户接口层的请求,然后通过资源库获取聚合实例,最后执行相应的命令操作,如下示例:

// 应用层的用例
public void cancelOrder(Long orderId) {
Order order = orderRepository.findById(orderId);
// 领域层的业务逻辑
order.cancel()
orderRepository.save(order);
}

领域层实现系统的核心业务逻辑,主要包含基于DDD业务建模产生的领域模型,这里的业务逻辑不同于应用层中的业务流程,如上代码示例;

基础设施层为其它各层提供通用的技术和基础服务,比如数据持久化功能。

二、传统分层架构的问题

DDD中资源库(Repository)用来获取或持久化聚合,每个聚合都拥有一个对应的资源库。由此可见资源库应该和聚合位于同一层,资源库接口定义应该位于领域层,而资源库接口实现需要依赖基础设施层的持久化机制,此时资源库接口实现放在哪一层对传统分层架构来说是个问题。

如果把资源库接口实现放在基础设施层,那么基础设施层就会向上依赖领域层,这样就违反了分层架构的原则:每层只能与位于其下方的层发生耦合。

或者可以放在领域层,但是这样会使领域层依赖数据持久化的实现细节,导致领域层不再是一个稳定层。

也可以放在应用层,不过和放在领域层会有同样的问题。

那有没有更好的方式呢?

有,采用依赖倒置,打破分层架构原则。

三、依赖倒置原则

依赖倒置(或依赖反转)原则(Dependency inversion principle,DIP),由Bob大叔提出,其定义如下:

高层模块不应该依赖于低层模块,两者都应该依赖于抽象。 抽象不应该依赖于细节,细节应该依赖于抽象。

我们把资源库接口实现放在基础设施层,让基础设施层向上依赖领域层。虽然这样违背了分层架构原则,但是却符合依赖倒置原则:领域层(高层模块)不依赖基础设施层(低层模块),两者都依赖于资源库接口(抽象)。采用了依赖倒置后,同时调整下基础设施层位置,此时分层架构如下图:

四、六边形架构

分层架构采用依赖倒置原则后,实际上已经不存在分层的概念了。无论是高层还是低层,都只依赖于抽象,好像把整个分层架构给推平了一样。推平后的分层架构如下图:

给推平的分层架构补上左侧对称的另一半,其结果就类似六边形架构,如下图是六边形架构。

六边形架构也叫端口和适配器。在这种架构中,针对系统输入输出的不同交互方式,比如http、rpc、mq、数据持久化等,都有与之对应的适配器,适配器又通过应用层API与内部进行交互。

六边形架构让应用程序能够以一致的方式被用户、程序、自动化测试、批处理脚本所驱动,而且能够让应用程序的边界更加清晰。有关六边形架构的详细信息可以查看 六边形架构原文翻译

五、为什么不选择整洁架构?

整洁架构是Bob大叔在其《架构整洁之道》一书中,对六边形架构和其他类似架构做了总结和抽象之后,提出的一种架构设计理念。

书中总结出,六边形架构和其他类似架构设计出来的系统,都具有相同的特点:

独立于框架:这些系统的架构并不依赖某个功能丰富的框架之中的某个函数。框架可以被当成工具来使用,但不需要让系统来适应框架。 可被测试:这些系统的业务逻辑可以脱离UI、数据库、Web服务以及其他的外部元素来进行测试。 独立于UI:这些系统的UI变更起来很容易,不需要修改其他的系统部分。 独立于数据库:我们可以轻易将这些系统使用的Oracle、SQL Server替换成Mongo、BigTable、CouchDB之类的数据库。因 为业务逻辑与数据库之间已经完成了解耦。 独立于任何外部机构:这些系统的业务逻辑并不需要知道任何其他外部接口的存在。

综合以上所有架构的设计理念,Bob大叔提出了整洁架构设计理念,如下图。

以上图中同心圆分别代表了软件系统的不同层次,通常越靠近中心,其所在的软件层次就越高。

整洁架构规定了层之间的依赖关系规则:内层(高层)不依赖外层(低层),六边形架构层之间的依赖关系也遵从此规则。

至此可以认为整洁架构是一种架构设计的指导思想,六边形架构是整洁架构的一种具体的架构设计。

六、总结

采用依赖倒置原则后的分层架构和六边形架构,实际上都符合整洁架构设计理念。但是六边形架构中使用端口与适配器,让应用程序能够以一致的方式被用户、程序、自动化测试、批处理脚本所驱动,同时能够让应用程序边界更加清晰,从而能更好地防止领域层和应用层逻辑泄露到外层。

七、参考

1.《实现领域驱动设计》

2.《架构整洁之道》

作者:京东零售 加文雄

来源:京东云开发者社区

DDD架构为什么应该首选六边形架构?的更多相关文章

  1. 【DDD】领域驱动设计实践 —— 架构风格及架构实例

    概述 DDD为复杂软件的设计提供了指导思想,其将易发生变化的业务核心域放置在限定上下文中,在确保核心域一致性和内聚性的基础上,DDD可以被多种语言和多种技术框架实现,具体的框架实现需要根据实际的业务场 ...

  2. IDDD 实现领域驱动设计-SOA、REST 和六边形架构

    上一篇:<IDDD 实现领域驱动设计-架构之经典分层> 阅读目录: SOA-面向服务架构 REST 与 RESTful 资源(Resources) 状态(State) 六边形架构 DDD ...

  3. SOA、REST 和六边形架构

    SOA.REST 和六边形架构 上一篇:<IDDD 实现领域驱动设计-架构之经典分层> 阅读目录: SOA-面向服务架构 REST 与 RESTful 资源(Resources) 状态(S ...

  4. WeText项目:一个基于.NET实现的DDD、CQRS与微服务架构的演示案例

    最近出于工作需要,了解了一下微服务架构(Microservice Architecture,MSA).我经过两周业余时间的努力,凭着自己对微服务架构的理解,从无到有,基于.NET打造了一个演示微服务架 ...

  5. NET实现的DDD、CQRS与微服务架构

    WeText项目:一个基于.NET实现的DDD.CQRS与微服务架构的演示案例 最近出于工作需要,了解了一下微服务架构(Microservice Architecture,MSA).我经过两周业余时间 ...

  6. 在 .NET Core 中应用六边形架构

    在本文中,您会看到一个Web API应用的模板,在.NET Core 中应用了六边形架构,并且里面包含了一些基础功能. 介绍 这是一个模板项目,里面集成了一些必备的基础功能,当我们需要开发一个新项目时 ...

  7. .NET应用架构设计—重新认识分层架构(现代企业级应用分层架构核心设计要素)

    阅读目录: 1.背景介绍 2.简要回顾下传统三层架构 3.企业级应用分层架构(现代分层架构的基本演变过程) 3.1.服务层中应用契约式设计来解决动态条件不匹配错误(通过契约式设计模式来将问题在线下暴露 ...

  8. WEB架构师成长之路-架构师都要懂哪些知识 转

    Web架构师究竟都要学些什么?具备哪些能力呢?先网上查查架构师的大概的定义,参见架构师修炼之道这篇文章,写的还不错,再查查公司招聘Web架构师的要求. 总结起来大概有下面几点技能要求: 一. 架构师有 ...

  9. 基于LAMP平台的网站架构(或Web系统架构)

    1.网站架构的前提(或者说需求) 我们公司是一电子商务的网站,因为线下家具建材项目的推广需求,从而有了我们公司的这个线上网站,在这里我贴一张公司的网站架构图. 总体来说网站规模不是太大,注册人数在15 ...

  10. 向架构师进军---&gt;系统架构设计基础知识

    假设你对项目管理.系统架构有兴趣,请加微信订阅号“softjg”,增加这个PM.架构师的大家庭 在解说系统架构设计之前,有必要补充一下架构相关的概念,因此本博文主要讲述架构.架构师和架构设计等相关的概 ...

随机推荐

  1. Springboot+Mysql 图书管理系统【源码+sql】

    java项目 学生图书管理系统 (源码+数据库文件)技术框架:java+springboot+mysql后端框架: Spring Boot.Spring MVC.MyBatis Plus前端界面: T ...

  2. 关于spring嵌套事务,我发现网上好多热门文章持续性地以讹传讹

    事情起因是,摸鱼的时候在某平台刷到一篇spring事务相关的博文,文章最后贴了一张图.里面关于嵌套事务的表述明显是错误的. 更奇怪的是,这张图有点印象.在必应搜索关键词PROPAGATION_NEST ...

  3. itext 生成pdf ----hello world

      iText是Java中用于创建和操作PDF文件的开源库.它是由Bruno Lowagie.Paulo Soares等人编写的.Ohloh报告称2001年以来[2],26个不同的贡献者进行了1万多次 ...

  4. [OpenCV-Python] 19 Canny 边缘检测

    文章目录 OpenCV-Python:IV OpenCV中的图像处理 19 Canny 边缘检测 19.1 原理 19.1.1 噪声去除 19.1.2 计算图像梯度 19.1.3 非极大值抑制 19. ...

  5. ASP.NET Response.Filter

    寫 ASP.NET 有時候會想要在畫面輸出前一刻進行攔截,並換掉 html 中的特定字元.例如網站中有許多頁面都有 www.google.com.tw 的超連結,我希望在測試機上可以把連結換成 www ...

  6. Git&GitHub简介与入手(二)

    四.GitHub 1.建账号,仓库 https://github.com/  用邮箱在官网注册: 增加远程库的地址取别名为origin,push为推送,fetch为取回: 2.推送操作 将本地当前所在 ...

  7. 2022-07-22:以下go语言代码输出什么?A:1;B:1.5;C:编译错误;D:1.49。 package main import “fmt“ func main() { var i

    2022-07-22:以下go语言代码输出什么?A:1:B:1.5:C:编译错误:D:1.49. package main import "fmt" func main() { v ...

  8. 2021-04-21:手写代码:Dijkstra算法。

    2021-04-21:手写代码:Dijkstra算法. 福大大 答案2021-04-21: Dijkstra算法是一种基于贪心策略的算法.每次新扩展一个路程最短的点,更新与其相邻的点的路程.时间紧,未 ...

  9. LC19. 删除链表的倒数第 N 个结点

    删除链表的倒数第N个结点(中等) Q:给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点. 示例: 示例一:输入:head = [1,2,3,4,5], n = 2 输出:[1,2,3, ...

  10. < Python全景系列-5 > 解锁Python并发编程:多线程和多进程的神秘面纱揭晓

    欢迎来到我们的系列博客<Python全景系列>!在这个系列中,我们将带领你从Python的基础知识开始,一步步深入到高级话题,帮助你掌握这门强大而灵活的编程语法.无论你是编程新手,还是有一 ...