应用程序框架实战十三:DDD分层架构之我见

摘要:
接下来,我们将介绍应用程序框架的另一个重要组件,即架构支持。大多数人从DDD分层架构中学习和实践。当然,DDD不是分层架构,而是DDD的技术结构。DDD分层体系结构通常类似于三层体系结构,但它为每个层提出了更具体的职责和构建块。DDD分层体系结构和传统的三层体系结构如下所示。DDD分层架构将域层置于核心。这些模型成为业务逻辑的主要场所。

  前面介绍了应用程序框架的一个重要组成部分——公共操作类,并提供了一个数据类型转换公共操作类作为示例进行演示。下面准备介绍应用程序框架的另一个重要组成部分,即体系架构支持。你不一定要使用DDD这样的架构,使用单层架构和普通三层架构一样可以,不过你如果希望获得更进一步的复用性和封装度,使用更加面向对象的技术是必经之程。

  我在2010年以前还在使用古老的ASP.NET WebForm和原始的Ado.Net。之前我有个观念:.NET技术发展太快,跟着微软屁股后面跑太累,所以只使用它一些原始的东西,自己封装一下也能满足工作上的需求。对于像Linq这样的技术只是随便看了下,特别是当时很多人告诉我Linq已死,千万别学,我当时很喜欢这样的言论,因为不学习新知识就有了充分的理由。

  到了2010年,我有一次上博客园,浏览了一些文章,发现充满各种缩写和名词,什么Dto、工作单元一类,我才知道新一代的.Net技术已经开始普及,我已经Out了。之后我开始学习EF和MVC,在刚开始接触EF的时候,我从一些博客了解到,为了发挥EF的威力,必须使用DDD进行设计。为了扫清拦路虎,我购买了几本DDD的书来学习,学习过程中才发现面向对象和敏捷开发才是关键,于是开始大量购书,一发不可收拾,四年时间买了接近两百本后,终于把基础补起来一点。

  DDD的核心思想是描述如何使用面向对象的方法对业务领域建模,怎样获得更好的领域模型。虽然看了不少DDD的资料,但还是感觉它异常抽象,另外面向对象的思想也很难进步,可能和前些年的编程习惯有关,已经习惯于从数据的角度考虑问题,形成了思维定势。

  DDD虽然抽象,但它还是提供了一些技术上的支持。大部分人都是从DDD分层架构入手来进行学习和实践,当然,DDD并不是分层架构,分层架构只是DDD的一个技术构造。下面简单介绍一下我对DDD分层架构的理解,由于我使用DDD的时间不长,我所描述的观点都是我自己的一些开发经验,不一定正确,欢迎各位高手批评指正,共同进步。

  DDD分层架构总体上和三层架构相似,不过对各层提出了更具体的职责和构造块。我也经常与一些在使用DDD分层架构的朋友交流,我问他们DDD分层架构与普通三层架构有何区别,大部分人都感觉差不多,除了一些名词术语有所变化。如果你也是这个感觉,那么可能本文对你是有帮助的,因为我明显感觉出它们之间有所不同。

  DDD分层架构与传统三层架构示意图如下。

 应用程序框架实战十三:DDD分层架构之我见第1张

(领域驱动设计分层架构示意图)

 应用程序框架实战十三:DDD分层架构之我见第2张

(传统三层架构示意图)

  DDD分层架构与传统三层架构最重要的区别可能是重心不同,即传统三层架构的重心在业务逻辑层,而DDD分层架构的重心在领域层。

  面向对象设计的核心是基于业务概念建模,并映射到代码中,这样的好处是减轻程序员将业务概念转换到技术的负担,因为更容易理解。传统三层架构虽然也把业务概念转换到实体层的Model对象,但实体层只是一个辅助设施,这些Model只是用来装数据的容器,作用并不显著。DDD分层架构把领域层提到核心地位,这些Model成为业务逻辑的一个主要放置场所。

  使用DDD分层架构的第一个好处就是业务逻辑高度内聚到领域层,换句话说,如果有逻辑问题,找领域层就对了。对于这一点,有些人认为传统三层架构也可以,找业务逻辑层不是一样吗?这可能是大多数对领域驱动设计分层架构认识无法突破的关键。

  虽然你可以按照分层架构的要求,把全部业务逻辑都写到BLL层,但你无法精确定位你需要的业务逻辑究竟处于什么位置,换句话说,你需要业务逻辑的一个唯一访问点。由于你无法轻易找到业务逻辑的访问点,所以产生冗余代码就再所难免,一段相同或相似的冗余代码会在多个地方产生,从而导致可维护性的降低。通过强制约束代码和目录规范以及提取公共方法可以缓解部分问题,但要从根本上解决,你还得向面向对象求救。

  那么,哪里是业务逻辑最好的落脚点,最直观,最容易被大家想到的唯一访问点在哪呢?比如你要处理一个订单,让你到其它地方去找处理订单的代码,你自然找起来困难。那么如果这段代码处于订单实体的内部,情况就大不相同了,你可以在最短的时间内找到它。在领域实体中内聚业务逻辑,可以为你创建一个业务逻辑的唯一访问点。大家以后需要某个逻辑的时候,先看看实体中有没有自己需要的,这样就能显著降低代码冗余,从而更好维护。

  所以,我的第一条DDD使用经验就是,使用充血模型,将业务逻辑尽量放到领域实体中。充血模型有很多争论,不过你大可不必理会别人的说法,自己实践才能出真知。用得不爽,你后面不用就是了,对你基本没啥影响。目前我使用充血模型,感觉它主要的问题是,如果采用分布式架构,比如中间采用WCF远程调用,需要通过一层专门的DTO来进行传输,而且需要增加一个远程外观的服务,会导致工作量上升。

  当把充血模型用起来以后,下一步是要把聚合用起来。聚合这个概念很好理解,就是包含关系。在UML中有两种包含关系,第一种叫聚合,表示比较弱的包含关系,聚合内部的东西在外面可以直接访问。第二种叫组合,即组成聚合,是很强的包含关系,表示外部的对象由内部的多个子对象组成,内部的子对象在外面不能直接访问,必须通过外部的对象间接引用。DDD虽然用了聚合这个词,但它表示UML中的组成聚合,所以它把外部的对象称为根,即聚合根,要访问内部对象,必须先访问聚合根。

  概念上的理解,除了能吹吹牛以外,没多大帮助。我在刚接触DDD的时候,也能理解聚合的概念,说起来一样口沫横飞,但真正用起来过了差不多一年。除了我反应比较迟钝以外,还有一个原因是被之前以数据为中心的思维定势所束缚。

  我也经常下载一些DDD的Demo来学习,但是这些例子大多都非常简单,所以我主要还是依靠看书和自己摸索。我刚开始的用法是一个表对应一个领域实体,每个领域实体对应一个仓储。我在使用的过程中,隐隐发现哪里不对,但是无法找出具体的原因。经过大半年,我也使用DDD开发了几个简单的项目,逐步积累了一些经验,在一次看书的时候,我突然领悟到我的DDD用法主要毛病是依赖关系混乱,而解决这些依赖关系的手段就是聚合。

  聚合的主要影响是显著减少仓储数量,以及集中管理高度依赖的相关实体。把高度相关的实体内聚到一个聚合中,可以把这些依赖关系封装到一个更小的空间,外部只与聚合根打交道,与聚合内部子对象的依赖关系就会明显降低。一个聚合对应一个仓储,而不是一个实体对象一个仓储,可以减少仓储数量,从而进一步降低依赖关系。

  后面我重新阅读了一些博客和书籍,发现别人其实都说清楚了,只是自己当时看过去没有理解而已,这真是纸上得来终觉浅 绝知此事要躬行。

  我的第二条DDD使用经验是,把高度相关的实体封装到聚合中,为每个聚合根创建一个仓储。

  观察上面的DDD分层架构示意图,会发现领域层只依赖于应用程序框架服务,仓储采用了接口分离模式将实现和接口分离到不同的程序集,领域层中只包含仓储的接口,这个设计让领域层非常纯净,和外部的依赖关系降到最低。这对我们意味着什么?更低的依赖让我们可以方便的对业务逻辑进行单元测试,特别是采用了TDD方式的话,这一点将显得尤其重要。我们可以在单元测试中使用模拟框架对仓储以及外部依赖进行模拟测试,从而大幅度提升业务逻辑的稳定性和健壮性。

  另外,观察传统三层架构,业务逻辑层一般直接依赖数据访问层,让单元测试变得困难,从而转向更粗粒度的集成测试。

  通过上面的分析,可以看到采用DDD分层架构可以获得比传统三层架构更好的可复用性、可维护性、可测试性等。

  当然不可能把所有业务逻辑全部放入领域实体中,有些功能需要操作多个实体,或者需要使用某些设计模式,这时候需要使用领域服务。这里的要点是尽量把领域服务的操作委托给领域实体,因为这样业务逻辑可以更加集中。

  DDD分层架构还有一些构造块,我会在后面的文章详细介绍。如果没有介绍到的,说明我还处于学习和摸索阶段,还没有多少心得,等我有些经验以后再告诉大家。

  现在来总结一下。

  使用DDD分层架构有哪些好处

  • 帮你更集中的管理业务逻辑。
  • 帮你降低各层间,以及各业务模块间的依赖关系。
  • 帮你更方便的进行单元测试。

  我的DDD分层架构使用经验

  • 使用充血模型,将业务逻辑尽量放到领域实体中,领域实体为业务逻辑提供一个唯一访问点。
  • 不能放入领域实体的逻辑,尽量放到领域服务,总之,业务逻辑应该高度内聚到领域层。
  • 把高度相关的实体封装到聚合中,为每个聚合根创建一个仓储。

  最后,提醒一下,我们使用一些DDD分层架构构造块,可能并不算真正用上了DDD。但是,我们的目标是使用DDD吗?不是,我们的目标是把业务逻辑做得更稳定,更好维护。所以不用在意自己使用的技术正不正宗,标不标准,只要比以前更好,就应该坚持下去。

  .Net应用程序框架交流QQ群: 386092459,欢迎有兴趣的朋友加入讨论。

  谢谢大家的持续关注,我的博客地址:http://www.cnblogs.com/xiadao521/

免责声明:文章转载自《应用程序框架实战十三:DDD分层架构之我见》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇iviewUI 时间选择器限制HTML #模态对话框 (完成版)下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

APP的UI自动化测试框架及平台化探索

顾铮,10年+测试及测试开发相关经验,2014年加入京东,曾主导设计开发UI测试框架,参与CI测试平台建设,现负责iOS侧的工具,框架建设。在UI自动化,性能测试,单元测试方面有较深入研究,在App,web端等有较丰富的测试开发和设计经验。 >>>> 写在前面 关于UI测试的文章,多数是通过架构的演进,或是重构,或是推翻重做来讲述的...

深入了解Windows句柄到底是什么(句柄是逻辑指针,或者是指向结构体的指针,图文并茂,非常清楚)good

总是有新入门的Windows程序员问我Windows的句柄到底是什么,我说你把它看做一种类似指针的标识就行了,但是显然这一答案不能让他们满意,然后我说去问问度娘吧,他们说不行网上的说法太多还难以理解。今天比较闲,我上网查了查,光是百度百科词条“句柄”中就有好几种说法,很多叙述还是错误的,天知道这些误人子弟的人是想干什么。 这里我列举词条中的关于句柄的叙述不...

《大规模分布式存储系统:原理解析与架构实战》.pdf

关注“Java后端技术全栈” 回复“面试”获取全套面试资料 分布式存储系统,将数据分散存储在多台独立的设备上。 传统的网络存储系统采用集中的存储服务器存放所有数据,存储服务器成为系统性能的瓶颈,也是可靠性和安全性的焦点,不能满足大规模存储应用的需要。 分布式网络存储系统采用可扩展的系统结构,利用多台存储服务器分担存储负荷,利用位置服务器定位存储信息,它不但提...

传统的SOA是否已经过时

  今天准备再聊下在当前微服务,中台和云原生技术下,传统的SOA是否已经过时这个话题。现在出去跟别人交流,谈到SOA的时候有些客户直接的反馈就是过时的技术怎么还在用?或者一说到SOA就认为过时了没必要采用,因此今天还是有必要就SOA是否过时进一步说明。 SOA的基本概念 我们可以来看下SOA本身的定义,即: SOA是一种架构方法,将传统的单片式应用打破...

常用的三层架构设计(转载)

常用的三层架构设计 软件系统最常用的一般会讲到三层架构,其实就是将整个业务应用划分为表示层、业务逻辑层、数据访问层等,有的还要细一些,通过分解业务细节,将不同的功能代码分散开来,更利于系统的设计和开发,同时为可能的变更提供了更小的单元,十分有利于系统的维护和扩展。 常见的三层架构基本包括如下几个部分,如图14-1所示。 图14-1 常见的三层架构 l 数...

把阿里巴巴的核心系统搬到云上,架构上的挑战与演进是什么?

作者丨张瓅玶(谷朴)阿里巴巴研究员 阿里巴巴核心系统作为全球最大规模、峰值性能要求最高的电商交易系统,在 2018 年之前只通过混合云弹性上云方式,为 双11 节约大量成本。直到 2019 年,阿里巴巴实现了核心交易系统全面上云并经历了 双11 峰值的考验。 在今天由极客邦科技举办的 ArchSummit 全球架构师峰会 2019 北京站上,阿里巴巴研究员...