领域驱动设计下系统层次结构风格(转载)
传统的三层架构
最简单的分层方式自然就是“表现层、业务逻辑层和数据访问层”,我们可以用下图来表示这个思想:
注意图中打虚线的“基础结构层”,从实践的表现上来看,这部分内容可能就是一些帮助类,比如 SQLHelper之类的,也可能是一些工具类,比如TextUtility之类。这些东西可以被其它各层所访问。而基于分层的概念,表现层只能跟业务逻辑层打交道,而业务逻辑层在数据持久化方面的操作,则依赖于数据访问层。表现层对数据访问层的内容一无所知。
从领域驱动的角度看,这种分层的方式有一定的弊端。首先,为各个层面提供服务的“基础结构层”的职责比较紊乱,它可以是纯粹的技术框架,也可以包含或处理一定的业务逻辑,这样一来,业务逻辑层与“基础结构层”之间就会存在依赖关系;其次,这种结构过分地突出了“数据访问”的地位,把“数据访问”与 “业务逻辑”放在了等同的地位,这也难怪很多软件人员一上来就问:“我的数据表该如何设计?”
领域驱动设计的分层
领域驱动设计将软件系统分为四层:基础结构层、领域层、应用层和表现层。与上述的三层相比,数据访问层已经不在了,它被移到基础结构层了。
-
基础结构层:该层专为其它各层提供技术框架支持。注意,这部分内容不会涉及任何业务知识。众所周知的数据访问的内容,也被放在了该层当中,因为数据的读写是业务无关的
-
领域层:包含了业务所涉及的领域对象(实体、值对象)、领域服务以及它们之间的关系。这部分内容的具体表现形式就是领域模型(Domain Model)。领域驱动设计提倡富领域模型,即尽量将业务逻辑归属到领域对象上,实在无法归属的部分则以领域服务的形式进行定义。有关领域对象和领域服务的内容,
-
应用层:该层不包含任何领域逻辑,但它会对任务进行协调,并可以维护应用程序的状态,因此,它更注重流程性的东西。在某些领域驱动设计的实践中,也会将其称为“工作流层”。应用层是领域驱动中最有争议的一个层次,也会有很多人对其职责感到模糊不清。比如,有些国外的开发人员会觉得,既然不包含领域逻辑,那又如何协调工作任务呢?
-
表现层:这个好理解,跟三层里的表现层意思差不多,但请注意,“Web服务”虽然是服务,但它是表现层的东西(ExtJS框架+Asp.net MVC框架)
从上图还可以看到,表现层与应用层之间是通过数据传输对象(DTO)进行交互的,数据传输对象是没有行为的POCO对象,它的目的只是为了对领域对象进行数据封装,实现层与层之间的数据传递。为何不能直接将领域对象用于数据传递?因为领域对象更注重领域,而DTO更注重数据。不仅如此,由于“富领域模型”的特点,这样做会直接将领域对象的行为暴露给表现层
系统结构
由于是领域驱动设计,本案例系统分层与传统分层略有不同。分为四层:展现层、应用服务层、领域层和基础结构层。展现层采用ASP.NET MVC框架实现;应用服务层则是一个WCF Service;领域层采用Entity Framework结合领域接口;基础结构层则为整个应用提供了IoC、Caching、Specifications、Repository等的具体实现。整个系统架构基本上可以以下图描述:
需要说明的是,在上图中的Domain Model和EdmRepository之间出现了双向依赖。其实,Domain Model只依赖于仓储(Repository)的接口,而EdmRepository是基于Entity Framework的一种仓储实现方式,它实现IRepository接口,同时也对Domain Model产生依赖,以获得对聚合根的访问。关键的一步在于,EnterpriseLibrary Library采用依赖注入,将EdmRepository注射到Domain Model中,于是,Domain Model根本不依赖于仓储的具体实现方式,保证了领域模型层面的纯净度。
仓储的实现可以用下图表述:
从本文还可以了解到,依赖注入是维持领域模型纯净度的一大利器;另一大利器是领域事件,我将在后续的文章中详述。对于本文开始的第三个问题,也就是仓储实现的可扩展性,将在下篇文章中进行讨论,包括的内容有:事务处理和可扩展的仓储框架的实现。
在面向对象的程序中,用户界面(UI)、数据库和其他支持代码,经常被直接写到业务对象中去。在UI和数据库脚本的行为中嵌入额外的业务逻辑。出现这种情况是因为层短期的观点看,它是使系统运行起来的最容易的方式。
当与领域相关的代码和大量的其他代码混在一起时,就很难阅读并理解了。对UI的简单改动就会改变业务逻辑。改变业务规则可能需要小心翼翼地跟踪UI 代码、数据库代码或者其他的程序元素。实现一致的模型驱动对象变都不切实际,而且自动化测试也难已使用.如果在程序的每一个行为中包括了所有的技术和逻辑,那么它必须很简单,否则会难以理解。
用户界面层 | 负责向用户显示信息,并且解析用户命令。外部的执行者有时可能会是其他的计算机系统,不一定非是人 |
应用层 | 定义软件可以完成的工作,并且指挥具有丰富含义的领域对象来解决问题。这个层附负责的任务对业务影响深远,对跟其他系统的应用层进行交互非常必要。这个层要保存简练。它不包括处理业务规则或知识。只是给下一层中相互协作的领域对象协调任务、委托工作。在这个层次中不反映业务情况的状态,但反映用户或程序的任务进度的状态 |
领域层 | 负责表示业务概念、业务状况的信息以及业务规则。尽管保存这些内容的技术细节由基础结构层兰完成。反映业务在的状态在该层中被控制和使用。这一层是业务软件的核心 |
基础结构层 | 为上册提供通用的技术能力;应用的消息发送、领域持久化,为用户加盟绘制窗口等。提供架构框架,基本结构层还可以支持这四层之间的交互模式 |
在一个复杂的程序进行层次划分。为每一层进行设计,每层都是内聚的而且只依赖于它的下层。采的用标准的架构模式来完成与上层松散关联。将所有与领域模型相关的代码集中在一层,并且家它与用户界面层、应用层和基础结构层的代码分离。领域对象可以将重点放在表达领域模型上,不需要关心他们自己的显示、存储和管理应用任务等内容。这样使模型发展得足够丰富和清晰,足以抓住本质的业务知识并实现它。