DDD(领域驱动设计)总结

基本概念:java

  领域驱动设计(简称 ddd)概念来源于2004年著名建模专家eric evans发表的他最具影响力的书籍:《domain-driven design –tackling complexity in the heart of software》(中文译名:领域驱动设计—软件核心复杂性应对之道)一书。,书中提出了“领域驱动设计(简称 ddd)”的概念。程序员

         领域驱动设计通常分为两个阶段:web

        1.   以一种领域专家、设计人员、开发人员都能理解的“通用语言”做为相互交流的工具,在不断交流的过程当中发现和挖出一些主要的领域概念,而后将这些概念设计成一个领域模型;spring

         2.   由领域模型驱动软件设计,用代码来表现该领域模型。领域需求的最初细节,在功能层面经过领域专家的讨论得出。数据库

 

       领域驱动设计告诉咱们,在经过软件实现一个业务系统时,创建一个领域模型是很是重要和必要的,由于领域模型具备如下特色:apache

     1.   领域模型是对具备某个边界的领域的一个抽象,反映了领域内用户业务需求的本质;领域模型是有边界的,只反应了咱们在领域内所关注的部分;编程

     2.   领域模型只反映业务,和任何技术实现无关;领域模型不只能反映领域中的一些实体概念,如货物,书本,应聘记录,地址,等;还能反映领域中的一些过程概念,如资金转帐,等;缓存

     3.   领域模型确保了咱们的软件的业务逻辑都在一个模型中,都在一个地方;这样对提升软件的可维护性,业务可理解性以及可重用性方面都有很好的帮助;安全

     4.   领域模型可以帮助开发人员相对平滑地将领域知识转化为软件构造;网络

     5.  领域模型贯穿软件分析、设计,以及开发的整个过程;领域专家、设计人员、开发人员经过领域模型进行交流,彼此共享知识与信息;由于你们面向的都是同一个模型,因此能够防止需求走样,可让软件设计开发人员作出来的软件真正知足需求;

     6.  要创建正确的领域模型并不简单,须要领域专家、设计、开发人员积极沟通共同努力,而后才能使你们对领域的认识不断深刻,从而不断细化和完善领域模型;

     7.  为了让领域模型看的见,咱们须要用一些方法来表示它;图是表达领域模型最经常使用的方式,但不是惟一的表达方式,代码或文字描述也能表达领域模型;

     8.  领域模型是整个软件的核心,是软件中最有价值和最具竞争力的部分;设计足够精良且符合业务需求的领域模型可以更快速的响应需求变化;

 

领域驱动设计中的一些基本概念:

1.实体(entity):

        根据eric evans的定义,”一个由它的标识定义的对象叫作实体”。一般实体具有惟一id,可以被持久化,具备业务逻辑,对应现实世界业务对象。

         实体通常和主要的业务/领域对象有一个直接的关系。一个实体的基本概念是一个持续抽象的生命,能够变化不一样的状态和情形,但老是有相同的标识。

 

须要注意的是:

         一些开发人员将实体当成了orm意义上的实体,而不是业务全部和业务定义的领域对象。在一些实现中采用了transaction script风格的架构,使用贫血的领域模型。这种认识上的混乱,在领域驱动架构中,不肯意在领域对象中加入业务逻辑而致使贫血的领域模型,同时还可能使混乱的服务对象激增。

 

2.值对象(value object)

        值对象的定义是:描述事物的对象;更准确的说,一个没有概念上标识符描述一个领域方面的对象。这些对象是用来表示临时的事物,或者能够认为值对象是实体的属性,这些属性没有特性标识但同时表达了领域中某类含义的概念。

 

        一般值对象不具备惟一id,由对象的属性描述,能够用来传递参数或对实体进行补充描述。

        做为实体属性的描述时,值对象也会被存储。在uml的类图上显现为一对多或一对一的关系。在orm映射关系上须要采用较复杂的一对多或一对一关系映射。

 

        关于实体与值对象的一个例子:好比员工信息的属性,如住址,电话号码均可以改变;然而,同一个员工的实体的标识将保持不变。所以,一个实体的基本概念是一个持续抽象的生命,能够变化不一样的状态和情形,但老是有相同的标识。

 

实体与值对象的区别

         实体具备惟一标识,而值对象没有惟一标识,这是实体和值对象间的最大不一样。

        实体就是领域中须要惟一标识的领域概念。有两个实体,若是惟一标识不同,那么即使实体的其余全部属性都同样,也认为是两个不一样的实体;一个实体的基本概念是一个持续抽象的生命,能够变化不一样的状态和情形,但老是有相同的标识。

        不该该给实体定义太多的属性或行为,而应该寻找关联,发现其余一些实体或值对象,将属性或行为转移到其余关联的实体或值对象上。

 

        若是两个对象的全部的属性的值都相同,咱们会认为它们是同一个对象的话,那么咱们就能够把这种对象设计为值对象。值对象在判断是不是同一个对象时是经过它们的全部属性是否相同,若是相同则认为是同一个值对象;而实体是否为同一个实体的区分,只是看实体的惟一标识是否相同,而无论实体的属性是否相同。

        值对象另一个明显的特征是不可变,即全部属性都是只读的。由于属性是只读的,因此能够被安全的共享;当共享值对象时,通常有复制和共享两种作法,具体采用哪一种作法还要根据实际状况而定。

        箴言:若是值对象时可共享的,它们应该是不可变的。(值对象应该保持尽可能的简单)

         值对象的设计应尽可能简单,不要让它引用不少其余的对象,由于本质上讲值对象只是表明一个值。

 

3.聚合及聚合根(aggregate、aggregate root):

        聚合是用来定义领域对象全部权和边界的领域模式。聚合的做用是帮助简化模型对象间的关系。聚合,它经过定义对象之间清晰的所属关系和边界来实现领域模型的内聚,并避免了错综复杂的难以维护的对象关系网的造成。聚合定义了一组具备内聚关系的相关对象的集合,咱们把聚合看做是一个修改数据的单元。

        划分aggregation是对领域模型的进一步深化,aggregation能阐释领域模型内部对象之间的深层关联.对aggregation的划分会直接映射到程序结构上.好比:ddd推荐按aggregation设计model的子包.每一个aggregation配备一个repository.aggregation内部的非root对象是经过导航得到的.        

        一个聚合是一组相关的被视为总体的对象。每一个聚合都有一个根对象(聚合根实体),从外部访问只能经过这个对象。根实体对象有组成聚合全部对象的引用,可是外部对象只能引用根对象实体。

         只有聚合根才能使用仓储库直接查询,其它的只能经过相关的聚合访问。若是根实体被删除,聚合内部的其它对象也将被删除。

         一般,咱们把聚合组织到一个文件夹或一个包中。每个汇集对应一个包,而且每一个汇集成员包括实体、值对象,domain事件,仓储接口和其它工厂对象。

 

 

聚合有如下一些特色:

  1. 每一个聚合有一个根和一个边界,边界定义了一个聚合内部有哪些实体或值对象,根是聚合内的某个实体;

  2. 聚合内部的对象之间能够相互引用,可是聚合外部若是要访问聚合内部的对象时,必须经过聚合根开始导航,绝对不能绕过聚合根直接访问聚合内的对象,也就是说聚合根是外部能够保持对它的引用的惟一元素;

  3. 聚合内除根之外的其余实体的惟一标识都是本地标识,也就是只要在聚合内部保持惟一便可,由于它们老是从属于这个聚合的;

  4. 聚合根负责与外部其余对象打交道并维护本身内部的业务规则

  5. 基于聚合的以上概念,咱们能够推论出从数据库查询时的单元也是以聚合为一个单元,也就是说咱们不能直接查询聚合内部的某个非根的对象;

  6. 聚合内部的对象能够保持对其余聚合根的引用;

  7. 删除一个聚合根时必须同时删除该聚合内的全部相关对象,由于他们都同属于一个聚合,是一个完整的概念。

 

如何识别聚合?

        聚合中的对象关系是内聚的,即这些对象之间必须保持一个固定规则,固定规则是指在数据变化时必须保持不变的一致性规则。

        当咱们在修改一个聚合时,咱们必须在事务级别确保整个聚合内的全部对象知足这个固定规则。

        做为一条建议,聚合尽可能不要太大,不然即使可以作到在事务级别保持聚合的业务规则完整性,也可能会带来必定的性能问题。

        有分析报告显示,一般在大部分领域模型中,有70%的聚合一般只有一个实体,即聚合根,该实体内部没有包含其余实体,只包含一些值对象;另外30%的聚合中,基本上也只包含两到三个实体。这意味着大部分的聚合都只是一个实体,该实体同时也是聚合根。

 

如何识别聚合根?

  若是一个聚合只有一个实体,那么这个实体就是聚合根;若是有多个实体,能够思考聚合内哪一个对象有独立存在的意义而且能够和外部直接进行交互。

       并非全部的实体都是汇集根,但只有实体才能成为汇集根。

 

4.工厂(factories):

       工厂用来封装建立一个复杂对象尤为是聚合时所需的知识,做用是将建立对象的细节隐藏起来。客户传递给工厂一些简单的参数,而后工厂能够在内部建立出一个复杂的领域对象而后返回给客户。当建立 实体和值对象复杂时建议使用工厂模式。

       不意味着咱们必定要使用工厂模式。若是建立对象很简单,使用构造器或者控制反转/依赖注入容器足够建立对象的依赖。此时,咱们就不须要通用工厂模式来建立实体或值对象。

 

       良好工厂的要求:

       每一个建立方法都是原子的。一个工厂应该只能生产透明状态的对象。对于实体,意味着建立整个聚合时知足全部的不变量。

      一个单独的工厂一般生产整个聚合,传出一个根实体的引用,确保聚合的不变量都有。若是对象的内部聚合须要工厂,一般工厂方法的逻辑放在在聚合根上。这样对外部隐藏了聚合内聚的实现,同时赋予了根确保聚合完整的职责。若是聚合根不是子实体工厂的合适的家,那么继续建立一个单独的工厂。

 

5.仓储(repositories):

        仓储是用来管理实体的集合。

         仓储里面存放的对象必定是聚合,缘由是domain是以聚合的概念来划分边界的;聚合做为一个总体概念,要么一块儿被取出来,要么一块儿被删除。外部访问不会单独对某个聚合内的子对象进行单独操做。所以,咱们只对聚合设计仓储。

         仓储还有一个重要的特征就是分为仓储定义部分和仓储实现部分,咱们在领域模型中定义仓储的接口,而在基础设施层实现具体的仓储。也符合按照接口分离模式在领域层定义仓储库接口的原则。

        注意:repositories自己是一种领域组件,但repositories的实现却不是领域层中的。

 

respositories和dao:

         dao和repository在领域驱动设计中都很重要。dao是面向数据访问的,是关系型数据库和应用之间的契约。

        repository:位于领域层,面向aggregation root。repository是一个独立的抽象,使用领域的通用语言,它与dao进行交互,并使用领域理解的语言提供对领域模型的数据访问服务的“业务接口”。

  dao方法是细粒度的,更接近数据库,而repository方法的粒度粗一些,并且更接近领域。领域对象应该只依赖于repository接口。客户端应该始终调用领域对象,领域对象再调用dao将数据持久化到数据 存储中。

  处理领域对象之间的依赖关系(好比实体及其repository之间的依赖关系)是开发人员常常遇到的典型问题。解决这个问题通 常的设计方案是让服务类或外观类直接调用repository,在调用repository的时候返回实体对象给客户端。

 

6.服务(services):

         服务这个词在服务模式中是这么定义的:服务提供的操做是它提供给使用它的客户端,并突出领域对象的关系。

         全部的service只负责协调并委派业务逻辑给领域对象进行处理,其自己并真正实现业务逻辑,绝大部分的业务逻辑都由领域对象承载和实现了。

         service可与多种组件进行交互,这些组件包括:其余的service、领域对象和repository 或 dao。

         一般,应用中通常包括:domain模型服务和应用层服务:

        *  domain services encapsulate domain concepts that just are not naturally modeled as things.

        *  application services constitute the application, or service, layer.

 

        当一个领域操做被视为一个重要的领域概念,通常就应该做为领域服务。 服务应该是无状态的。

        设计实现领域服务来协调业务逻辑,只在领域服务中实现领域逻辑的调用。

        领域服务逻辑须以很是干净简洁的代码实现。所以,咱们必须实现对领域低层组件的调用。一般应用的调用,例如仓储库的调用,建立事务等,不该该在这里实现。这些操做应该在应用层实现。

          一般服务对象名称中都应包含一个动词。 service接口的传入传出参数也都应该是dto,可能包含的工做有领域对象和dto的互转换以及事务。

 

      服务的3个特征:

  a. 服务执行的操做涉及一个领域概念,这个领域概念一般不属于一个实体或者值对象

  b. 被执行的操做涉及到领域中其它的对象

  c. 操做时无状态的

推荐:最好显式声明服务,由于它建立了领域中一个清晰的特性,封装了一个概念领域层服务和基础设施层服务:均创建在领域实体和值对象的上层,以便直接为这些相关的对象提供所需的服务;

 

领域服务与domain对象的区别

        通常的领域对象都是有状态和行为的,而领域服务没有状态只有行为。须要强调的是领域服务是无状态的,它存在的意义就是协调领域对象共同完成某个操做,全部的状态仍是都保存在相应的领域对象中。

        一般,对开发人员来讲建立不该该存在的服务至关容易;要么在服务中包含了本应存在于领域对象中的领域逻辑,要么扮演了缺失的领域对象角色,而这些领域对象并无做为模型的一部分去建立。

 

 

7.domain事件

        domain event模式最初由udi dahan提出,发表在本身的博客上:http://www.udidahan.com/2009/06/14/domain-events-salvation/

        企业级应用程序事件大体能够分为三类:系统事件、应用事件和领域事件。领域事件的触发点在领域模型(domain model)中。它的做用是将领域对象从对repository或service的依赖中解脱出来,避免让领域对象对这些设施产生直接依赖。它的作法就是当领域对象的业务方法须要依赖到这些对象时就发出一个事件,这个事件会被相应的对象监听到并作出处理。

        经过使用领域事件,咱们能够实现领域模型对象状态的异步更新、外部系统接口的委托调用,以及经过事件派发机制实现系统集成。另外,领域事件自己具备自描述性。它不只可以表述系统发生了什么事情,并且还可以描述发生事件的动机。

         domain事件也用表进行存储。

 

8.DTO

       dto- datatransfer object(数据传输对象):dto在设计之初的主要考量是以粗粒度的数据结构减小网络通讯并简化调用接口。

 

领域驱动架构与n层架构设计

领域驱动架构

        eric  evans的“领域驱动设计- 应对软件的复杂性“一书中描述和解释了建议的n层架构高层次的图:

 

user interface:

        该层包含与其余系统/客户进行交互的接口与通讯设施,在多数应用里,该层可能提供包括web services、rmi或rest等在内的一种或多种通讯接口。该层主要由facade、dto和assembler三类组件构成,三类组件均是典型的j2ee模式。

        dto的做用最初主要是以粗粒度的数据结构减小网络通讯并简化调用接口。在领域驱动设计中,采用dto模型,能够起到隐藏领域细节,帮助实现独立封闭的领域模型的做用。

        dto与领域对象之间的相互转换工做多由assembler承担,也有一些系统使用反射机制自动实现dto与领域对象之间的相互转换,如apache common beanutils。

        facade的用意在于为远程客户端提供粗粒度的调用接口。facade自己不处理任何的业务逻辑,它的主要工做就是将一个用户请求委派给一个或多个service进行处理,同时借助assembler将service传入或传出的领域对象转化为dto进行传输。

 

application:

         application层中主要组件就是service。这里须要注意的是,service的组织粒度和接口设计依据与传统transaction script风格的service是一致的,可是二者的实现却有质的区别。

  transaction script(事务脚本)的核心是过程,经过过程的调用来组织业务逻辑,业务逻辑在服务(service)层进行处理。大部分业务应用均可以被当作一系列事务。

         transaction script的特色是简单容易理解,面向过程设计。  若是应用相对简单,在应用的生命周期里不会有基础设施技术的改变,尤为是业务逻辑不多会变更,采用transaction script风格简单天然,性能良好,容易理解。

        transaction script的缺点在于,对于复杂的业务逻辑难以保持良好的设计,事务之间的冗余代码不断增多。应用架构容易出现“胖服务层”和“贫血的领域模型”。同时,service层积聚愈来愈多的业务逻辑,致使可维护性和扩展性变差

  领域模型属于面向对象设计,领域模型具有本身的属性行为和状态,领域对象元素之间经过聚合配合解决实际业务应用。可复用,可维护,易扩展,能够采用合适的设计模型进行详细设计。缺点是相对复杂,要求设计人员有良好的抽象能力。

        transactionscript风格业务逻辑主要在service中实现,而在领域驱动设计的架构里,service只负责协调并委派业务逻辑给领域对象进行处理。所以,咱们能够考察这一点来识别系统是transaction script架构仍是domain model架构。在实践中,设计良好的领域设计架构在开发过程中也容易向transaction script架构演变。

 

domain:

        domain层是整个系统的核心层,该层维护一个使用面向对象技术实现的领域模型,几乎所有的业务逻辑会在该层实现。domain层包含entity(实体)、valueobject(值对象)、domain event(领域事件)和repository(仓储)等多种重要的领域组件。

 

infrastructure:

        infrastructure(基础设施层)为interfaces、application和domain三层提供支撑。全部与具体平台、框架相关的实现会在infrastructure中提供,避免三层特别是domain层掺杂进这些实现,从而“污染”领域模型。infrastructure中最多见的一类设施是对象持久化的具体实现。

 

n层架构设计

        层(layers)被视为构成应用或服务的水平堆叠的一组逻辑上的组件。它们帮助区分完成不一样任务的组件,提供一个最大化复用和可维护性的设计。简言之,是关于在架构方面应用关注点分离的原则。         在传统的多层架构中,每一个解决方案的组件必须分隔到不一样的层。每层的组件必须内聚并且有大约相同的抽象级别。每一个一级层应该和其余的一级层松耦合。

        从最底层的抽象级别看,例如第1层。这是系统的基础层。这些抽象的步骤是一步一步的最后到最顶层。

        多层应用的关键在于对依赖的管理。传统的多层架构,层内的组件只能和同级或者低级层的组件交互。这有利于减小不一样层内组件的依赖。一般有两种多层架构的设计方法:严格和灵活的。          *   “严格的层设计”限定层内的组件只能和同一层、或者下一层的组件通讯。即第n层只能和第n-1层交互,n-1层只能和n-2层交互,等等。

         *  “灵活的层设计”容许层内的组件和任何低级别层交互。这种设计中,第n层能够和n-1,n-2层交互。

        这种设计因为不须要对其余层进行重复的调用,从而能够提升性能。然而,这种设计不提供层之间的同层隔离级别,使得它难以在不影响多个高级层的时候替换一个低级的层。

        因为层之间是经过定义明确的接口进行交互这一事实,很容易为各层添加替代的实现(例如 mock  and stubs)。

         由于高层的组件只能和底层的交互,在单独的组件上进行测试是很容易的。

使用层的好处  -  功能容易肯定位置,解决方案也就容易维护。层内高内聚,层间松耦合使得维护/组合层更容易。 -  其余的解决方案能够重用由不一样层暴露的功能。 -  当项目按逻辑分层时,分布式的部署更容易实现。 -  把层分布到不一样的物理层能够提升可伸缩性;而后这一步应该进行仔细的评估,由于可能对性能带来负面影响。

 

面向领域架构的分层:

        在面向领域架构中,关键是要清楚界定和分离领域模型层和其他的层。

 

领域驱动与项目开发

         通常适合结合使用scrum(适用于项目管理)和xp(适用于软件开发目标)方法对处理ddd实施项目。敏捷方法注重于交付商业价值,而ddd侧重于结合软件系统和业务模型。此 外,就ddd迭代的特性来讲,scrum或dsdm这样的敏捷方法对项目管理来讲也是更好的框架。

       ddd迭代周期的项目管理模型如图所示。

本图根据《domain driven design and development in practice》一文中插图进行了部分修改。

  领域建模结束时能够开始领域驱动设计。关于如何开始实现领域对象模型,ramnivas laddad推荐以下的步骤。他强调要更侧重于领域模型中的领域对象,而不是服务。

       *   从领域实体和领域逻辑开始。

       *   不要一开始就从服务层开始,只添加那些逻辑不属于任何领域实体或值对象的服务。

       *   利用通用语言、契约式设计(dbc)、自动化测试、  ci和重构,使实现尽量地与领域模型紧密结合。

 

设计领域模型的通常步骤:

       1.   根据需求创建一个初步的领域模型,识别出一些明显的领域概念以及它们的关联,关联能够暂时没有方向但须要有(1:1,1:n,m:n)这些关系;能够用文字精确的没有歧义的描述出每一个领域概念的涵义以及包含的主要信息;

       2.   分析主要的软件应用程序功能,识别出主要的应用层的类;这样有助于及早发现哪些是应用层的职责,哪些是领域层的职责;

       3.   进一步分析领域模型,识别出哪些是实体,哪些是值对象,哪些是领域服务;

       4.   分析关联,经过对业务的更深刻分析以及各类软件设计原则及性能方面的权衡,明确关联的方向或者去掉一些不须要的关联;

       5.   找出聚合边界及聚合根,这是一件颇有难度的事情;由于你在分析的过程当中每每会碰到不少模棱两可的难以清晰判断的选择问题,因此,须要咱们平时一些分析经验的积累才能找出正确的聚合根;

       6.   为聚合根配备仓储,通常状况下是为一个聚合分配一个仓储,此时只要设计好仓储的接口便可;

       7.   走查场景,肯定咱们设计的领域模型可以有效地解决业务需求

       8.   考虑如何建立领域实体或值对象,是经过工厂仍是直接经过构造函数;

       9.   停下来重构模型。寻找模型中以为有些疑问或者是蹩脚的地方,好比思考一些对象应该经过关联导航获得仍是应该从仓储获取?聚合设计的是否正确?考虑模型的性能怎样,等等;

         领域建模是一个不断重构,持续完善模型的过程,你们会在讨论中将变化的部分反映到模型中,从而是模型不断细化并朝正确的方向走。

 

  从设计和实现的角度来看,典型的ddd框架应该支持如下特征。

       *   应该是一个以pojo为基础的架构。

       *   应该支持使用ddd概念的业务领域模型的设计和实现。

       *   应该支持像依赖注入(di)和面向方向编程(aop)这些概念的开箱即用。

       *   与单元测试框架整合。

       *   与其它java/java ee框架进行良好的集成,好比jpa、hibernate、toplink等。

 

一些反模式:

       *   贫血的领域对象

       *   重复的dao

       *   肥服务层:服务类在这里最终会包含全部的业务逻辑。

       *   依恋情结(feature envy):函数对某个类的兴趣高过对本身所处类的兴趣。

 

一些思考

1.   创建完整自封闭的领域模型。

        领域驱动架构相对比较容易理解,但创建一个完整自封闭的领域模型却很困难。“领域模型”是一个针对业务逻辑抽象的分析模型,它反映出对领域问题的总体描述。领域模型不是编程的实现模型,而是一组抽象概念的集合。一个领域概念不必定映射成一个类,也有可能会映射不少的类(包括多个实体或值对象)。领域需求的最初细节,在功能层面经过领域专家的讨论得出。领域专家并不必定须要熟知软件开发领域的知识,相反强调的是具备领域中的相关知识。领域需求在相互讨论中不断获得细化,还有可能在开发过程出现需求的反复或变动,这都要求领域模型的创建完善是一个反复重构的过程。敏捷开发是一种应对快速变化的需求的一种软件开发能力。强调程序员团队与业务专家之间的紧密协做、面对面的沟通(认为比书面的文档更有效)、频繁交付新的软件版本、紧凑而自我组织型的团队、可以很好地适应需求变化的代码编写和团队组织方法。故采用敏捷开发有利于领域模型的创建完善,以更能符合用户的实际需求。

      关于领域模型分析存在有多种分析方法。也许并非能常常能有机会去实践这些分析方法或分析领域模型。但关于领域驱动架构的理解,有助于帮助咱们去理解领域驱动的设计,实现一些高内聚、低耦合的代码实现。

 

2.  领域服务建模

          创建和识别领域服务也比较容易出错。一般的ssh分层架构与领域驱动架构相近,而ssh架构开发更容易致使transaction script架构而非领域驱动架构。在ssh分层架构上,开发人员更容易创建”贫血”模型,而在service里实现业务逻辑。而ddd强调“充血模型”,“薄”service层。创建领域服务须要识别出领域业务逻辑,并将业务实现到领域模型中。一方面,业务需求充满着变化,在开发过程中难以把握。当业务不明需求不清时,“贫血模型”就更容易被人接受。另外一方面,在构建领域模型时,orm映射显示十分重要而且也很是复杂,包括类继承体系与数据库的映射,抓取策略和缓存管理在内的一系列问题等.“贫血模型”有时会简化这种映射关系,同时,在处理对象依赖关系上显得更加灵活性。而领域模型强调了领域边界,对领域对象的访问老是经过聚合根开始,在有时候,模型的某些遍历会带来更大的性能和稳定性上的问题。而解决这些问题时,又经常会从实效性上出发而牺牲模型个别的清晰性和纯洁性。

 

3.领域对象、领域服务以及repository之间的互相依赖

        在实际开发中,开发人员会常常须要处理领域对象之间的依赖关系,以及领域对象与repository间的依赖。一般可能的方案是让service或façade直接调用repository,从而得到返回的领域对象。这种方式致使各层间的依赖,一般咱们应该考虑解耦这种依赖。当前实现组件解耦经常使用的技术无非是:控制反转(ioc)、依赖注入(di)、面向方面编程(aop)以及分布式服务接口。所以,解决依赖的一种思路利用di或aop将repository和服务注入到领域对象中。spring框架提供了相关的机制。在spring环境中,利用spring实例化对象,注入依赖,将服务、repository等领域对象联系起来。