`

实战DDD(Domain-Driven Design领域驱动设计:Evans DDD)

阅读更多

http://www.jdon.com//mda/ddd.html

 2004年著名建模专家Eric Evans发表了他最具影响力的著名书籍:Domain-Driven Design –Tackling Complexity in the Heart of Software(中文译名:领域驱动设计 2006年3月清华出版社译本,或称 Domain Driven-Design architecture [Evans DDD])。

  Martin Fowler作序说;“希望本书是一本非常有影响力的书籍,....... Eric最值得我尊敬的一个方面是他敢于讨论还未取得成功的事情”,其实,时值今年2006年,DDD开发框架已经层出不穷(如RoR、RIFE、JdonFramework等),我们项目软件包结构都变成了这样:xxx.model;xxx.service,DDD思想已经遍地开花,不能再说不成功了。

  DDD是告诉我们如何做好业务层!并以领域驱动设计思想来选择和合适的框架,现在很多人总是先接触框架架构,不知道DDD,结果编出的程序很难拓展,业务逻辑都写在Service中,造成模型失血,成为数据的容器(见这个案例)。这些都是伪善OO,正确的学习顺序应该是首先学习DDD,再根据DDD和业务指导如何使用框架,如Spring Seam等。

  本文以基于JdonFramework开发的JiveJdon3.0说明DDD方法的实战应用。

  首先必须认识到:领域建模是一种艺术的技术,不是数学的技术,它是用来解决复杂软件快速应付变化的解决之道(快速适应需求变化的软件复用)。

  我们知道软件的产生过程是:分析、设计、编程、测试、部署。过去,分析领域和软件设计是分裂的,分析人员从领域中收集基本概念;而设计必须指明一组能北项目中适应编程工具构造的组件,这些组件必须能够在目标环境中有效执行,并能够正确解决应用程序出现的问题。 模型驱动设计(Model-Driven Design)抛弃了分裂分析模型与设计的做法,使用单一的模型来满足这两方面的要求。这就是领域模型。

  单一的领域模型同时满足分析原型和软件设计,如果一个模型实现时不实用,重新寻找新模型。如果模型没有忠实表达领域关键概念时,也必须重新寻找新的模型。 建模和设计成为单个迭代循环。将领域模型和设计紧密联系。因此,建模专家必须懂设计,会编程。

分层架构

  最初层次只分为三层:表现层、业务层和持久层;DDD其实告诉我们如何让实现业务层!

  一位道友曾经请教层次的职责,对服务Service提出疑问。根据Eric的理论,业务层将细分为两个层次:应用层和领域层。它们的定义是:应用层:定义软件可以完成的工作,并且指挥具有丰富含义的领域对象来解决问题,保持精练;不包括业务规则或知识,无业务情况的状态; 领域层:负责表示业务概念、业务状态的信息和业务规则,是业务软件核心。

  层次之间必须清晰分离,每个层都是内聚的,并且只依赖它的下层,为了实现各层的最大解耦,Ioc模式和Ioc容器是目前最好的选择,JdonFramework使用基于PicoContainer的Ioc容器实现了各层的松耦合;

  Eric特别指出:那种将业务逻辑交由业务界面处理的快速UI方式是旁门左道。希望象C/S结构那样可视化拖拖图形就完成的软件开发是一种错误的方向,开发时快速,难于维护和扩展,虽然使用J2EE技术,其实是一种伪多层技术。可惜,有很多国人在疯狂开发这类工具,大有不撞南墙不低头之势,并且疯狂误导很多非专业人士,可悲可叹!如果对这段言论持不同意见,建议你购买"领域驱动设计"这本译书,见P53页。

领域模型种类

  传统模型分为两种:实体(Entity)和值对象(Value Object),现在服务(Service)成为第三种模型元素。

  实体(Entity)定义:通过一系列连续性(continuity)和标识(identity ID)来定义;个人认为它和分析领域的四色原型中的PPT原型非常类似,可以看成是PPT原型延续。

  实体必须拥有自己的唯一ID,主键,如果没有一个ID标识,为每个实例加上一个具有唯一性ID,可能是内部使用。 如JiveJdon3.0中jdonframework.xml中模型增删改查CRUD配置定义:

<model key="forumId"  class="com.jdon.jivejdon.model.Forum">
    .....    
</model>

  其中,forumId是模型com.jdon.jivejdon.model.Forum的主键,唯一ID,每个模型必须有一个专家。

  值对象(Value Object):如果一个对象代表了领域的某种描述性特征,且没有概念性的标识。个人认为它是四色原型中Description原型延续。如果我们只关心模型中一个元素的属性,那么把这个元素划为值对象。值对象是不可变的,不要给它任何标识,避免实体的维护性,降低设计复杂性。我们不关心值对象是哪个实例。

  在JiveJdon3.0中,ForumState是一个值对象,它表示论坛当前最新帖子、论坛的主题数量和帖子数量,它的根对象是Forum,是被内聚嵌入到Forum这个实体模型中的,代码如下:

package com.jdon.jivejdon.model;

 

/**
* Forum State ValueObject
* this is a embeded class in Forum.
* @author <a href="mailto:banqiao@jdon.com">banq</a>
*
*/
public class ForumState {

  private int threadCount = 0; //主题数量

  
  private int messageCount = 0;//帖子数量


  private ForumMessage lastPost; //最新帖子

 

  public int getMessageCount() {
    return messageCount;
  }  

  ......
}

  同样ForumThreadState是也是一种值对象,根据Eric的值对象设计,ForumThreadState和ForumState是可以合并成一个对象的,值对象中没有ID等唯一标识。

forum

 

  Eric认为:服务Service是描述领域概念最自然的方式,是四色原型的MI原型的延续, 优秀服务3个特征:
  1.与领域概念相关的操作行为、但不是实体和值对象中固有的部分。
  2.接口根据领域模型中其他元素定义
  3.操作是无状态的。

  在JiveJdon3中,com.jdon.jivejdon.service.ForumService和Forum实体模型及其值对象ForumState共同完成领域模型,其中ForumService属于应用服务层;而后两者属于领域层;其他服务ForumMessageService、AccountService和UploadService等都是此类性质。

领域对象的生命周期Scope

  Spring 1.x刚出来时确实忽悠了大家一把,因为他没有领域对象的生命周期支持,直到Spring 2.0才将如new Bean scope,当初那些疯狂捧Spring 1.x 臭脚的所谓高手是不是还是基于数据库驱动的思维,根本没有真正OO模式思维,当今天JBoss Seam、Scopes等框架开始重视对象生命周期支持后,曾经发生在Jdon社区争战硝烟已经过去,成为历史。

  Eric认为:每个对象独有器生命周期,一个对象在创建以后,可能要经历各种不同的状态,并最终消亡。 对象生命周期由长短:临时对象;常驻内存;有的与其他对象存在复杂的依赖关系;状态变化时必须满足一些不变量的约束条件。 如何管理这些对象提出挑战!处理不好会偏离MDD的方向。

  在生命周期中维护对象的完整性。避免模型由于管理生命周期的复杂性而陷入困境。有 三个模式来处理:聚合(Aggregate):定义清晰的所有权和边界使模型更加紧凑,避免出现盘根错节的对象关系网;工厂(Factory)和组合(Respository)。

  当一个对象生命周期之始,使用工厂和组合提供了访问和控制模型对象的方法,完善了MDD。 建立聚合的模型,并且把工厂和组合加入设计中来,可以使我们系统地对模型对象进行管理。 聚合圈出一个范伟,在这个范围中,对象无论在哪个生命周期,保持不变性。

  在JiveJdon3.0中,值对象ForumState是被聚合在实体模型Forum中,Forum作为ForumState的一个根,由于它们数据必须保持一致性,不变量(invariant)是指无论何时发生数据变化必须满足一致性规则,由于根控制了访问,就无法绕过它修改内部元素,例如,如果没有Forum实体对象这个根,就无法去修改对象状态ForumState,ForumState获得是通过Forum的getter方法获得的。

  ForumState和Forum的分离有可以使修改论坛状态数据(当发一个新帖时,必须更新当前论坛的最新帖子为该新帖),不会影响到Forum其他元素,特别是使用事务锁定时,不必锁住整个对象,见"领域驱动设计"书籍P92。

  另外,ForumThread和ForumMessage的关联关系必设定成单向的,而不是双向的,因为领域建模中,关联越简单越好。

  在JiveJdon3.0中,你可能注意到有一个com.jdon.jivejdon.service.factory.ForumBuilder,所有实体模型对象的获得都是从这个工厂创建出来的,我曾经徘徊过:这个工厂类是否应该属于持久层,因为JiveJdon3.0持久层没有使用Hibernate这样O/R Mapping框架,而是直接使用SQL,但是从持久层输出的都是对象,这是必须坚持的一个设计原则(好像是MF的一个什么元数据模式) 。

  但是,Eric明确告诉我们,领域模型的工厂属于应用层,页就是还是应该处于业务层的,这样好处很多,业务层设计根本无需从Hibernate等持久层框架获得,而是从自己的工厂获得。

  组合(Respository)又被翻译成仓储,我认为组合合适,主要用来返回一批对象,查询组合常用来返回批量查询结果,JdonFramework两个快速开发支持:批量查询其实应该是Respository的实现,实际也是过去Master-details的一种查询实现。

  以com.jdon.jivejdon.presentation.action.ThreadListAction为例子,其功能是查询论坛Forum下所有主题ForumThread,并分页显示,实现效果按这里,我们在customizeListForm方法中将根Model Forum设置进入,在threadList.jsp中,我们使用struts的标签库logic:iterator来遍历组合对象threadListForm中的ForumThread集合。

JiveJdon中聚合根和边界

ddd

失血模型

  MF(Martin Fowler)曾经提出有名的贫血模型或失血模型,让我们好生迷惑和彷徨,他认为实体模型对象中只有弱行为setter和getter方法,没有真正行为,好像缺少血液的人,不和谐了,不少高手又被忽悠了,大谈贫血模型。

  其实,Eric已经认为,在DDD中,领域中一些概念不能作为模型中的对象来处理的,如果将这些功能概念强行加给实体对象和值对象,破坏模型中对象的定义,人为添加没有意义的对象。服务是描述领域概念最自然的方式。

  为了在这些大师之间取得一个平衡,有人将Model的持久化操作(CRUD行为)整入到领域模型中,这是不是违背当初Dao模式初衷,Dao模式其实是桥模式和适配器模式组合(见SUN的J2EE核心模式)。

  无论如何,我们的DDD项目中都是以失血模型存在着,所以,Eric呼唤:建模专家必须懂得实现,懂得软件技术,MF可能会听进去的。

分享到:
评论

相关推荐

    Domain-Driven-Design-Distilled.zip

    DDD(Domain-Driven Design 领域驱动设计)是由Eric Evans最先提出,目的是对软件所涉及到的领域进行建模,以应对系统规模过大时引起的软件复杂性的问题。整个过程大概是这样的,开发团队和领域专家一起通过 通用...

    Domain-Driven Design

    'Eric Evans has written a fantastic book on how you can make the design of your software match your mental model of the problem domain you are addressing. 'His book is very compatible with XP. It is ...

    Domain Driven Design (DDD Classic by Eric Evans).pdf

    在微服务(Microservices)架构实践中,人们大量地借用了DDD中的概念和技术...在微服务设计中应该首先识别出DDD中的聚合根(Aggregate Root);还有在微服务之间集成时采用DDD中的防腐层(Anti-Corruption Layer, ACL)

    Applying Domain-Driven Design and Patterns: With Examples in C# and .NET

    领域驱动设计与模式实战,英文版,效果应该还不错,当然好坏自己还得看,至少不会太让人失望的,中文翻译上有哪个啥的。The main focus of the book is how a Domain Model could be constructed to be clean, yet ...

    Implementing Domain Driven Design

    With Implementing Domain-Driven Design, Vaughn has made an important contribution not only to the literature of the Domain-Driven Design community, but also to the literature of the broader enterprise...

    Domain-Driven Design Reference:Definitions and Pattern Summaries

    本书是Eric Evans对他自己写的《领域驱动设计-软件核心复杂性应对之道》的一本字典式的参考书,可用于快速查找《领域驱动设计》中的诸多概念及其简明解释。书是英文版的,2015年3月修订版,我已经加了目录,方便大家...

    Domain Driven Design by Eric(有目录版)

    但不管怎样,请你抛开偏见,好好的研读一下Eric Evans的《领域驱动设计》,如果有认知升级的感悟,恭喜你,你进阶了。我个人认为DDD最大的好处是将业务语义显现化,把原先晦涩难懂的业务算法逻辑,通过领域对象...

    论文研究-基于领域驱动设计的应用系统模型.pdf

    领域驱动设计(Domain-Driven Design,DDD)是Evans提出来的用来处理软件系统核心复杂性的方法。该方法的有效性在实践中得到证明,但是方法在细节上存在不够清晰、对设计人员素质要求高等问题。在对大量业务系统进行...

    php-ddd-cargo-sample:PHP 7 Eric Evans DDD书中使用的货物示例版本

    PHP DDD货物样品 Eric Evans域驱动设计书中使用的货物样本PHP 7端口 装货样品 经过两年的不活动后,可以使用新版本PHP DDD Cargo Sample...我们想借助Eric Evans在《 Domain-Driven Design: Tackling Complexity in the

    Domain Driven Design: Tracking complexity in the hearts of software

    Domain-Driven Design: Tackling Complexity in the Heart of Software By Eric Evans Publisher: Addison Wesley Pub Date: August 20, 2003 ISBN: 0-321-12521-5 Pages: 560

    Domain-Driven Design Tackling Complexity in the Heart of Software(原版)

    来自著名建模专家Eric Evans经典的DDD 设计方法,微服务时代的另一种选择。

    领域驱动2017大会

    Eric Evans的“Domain-Driven Design领域驱动设计”简称DDD,Evans DDD是一套综合软件系统分析和设计的面向对象建模方法,本站Jdon.com是国内公开最早讨论DDD网站之一,可订阅DDD专题。初学者学习DDD可从研究本站...

    66套Java SpringBoot系统源码集合超值划算.zip

    参考Eric Evans提出的DDD(Domain-Driven Design 领域驱动设计),结合springboot,mybatis+,动态数据源(读写分离)等搭建的DDD架构ddd_springboot_demo-master.zip 大学期间做的各样项目,有JavaPythonJavaScriptVert....

    领域驱动设计模型DomainDrivenDesign

    Eric Evans所著的《领域驱动设计》(Domain-Driven Design:通常简称为“DDD”)一书可以说是经典中的经典,虽然“领域”的概念早就存在,但是直到这本书的出现,才让人们真正开始认真审视软件的构建,相信你看了这...

    JiveJdon v4.6.1.zip

    JiveJdon核心领域模型图如下,建模过程来自 实战DDD(Evans DDD:Domain-Driven Design领域驱动设计) : 新架构 JiveJdon 业务层采取了组件动态设计的面向构件架构,能够简单方便拓展新功能,不再发生牵一动百的错误...

    NET-Microservices-Architecture-for-Containerized-NET-Applications-中文版.rar

    2004年Eric Evans 发表Domain-Driven Design –Tackling Complexity in the Heart of Software (领域驱动设计),简称Evans DDD。领域驱动设计分为两个阶段: 以一种领域专家、设计人员、开发人员都能理解的通用...

    dddlib:DDD(域驱动设计)库,源于Eric Evans的书

    是一个领域驱动设计(Domain Driven Design,简称DDD)类库,它的目的是: 为基于DDD的开发范式提供基本的接口和抽象,实现一致性。 支持业务代码和技术代码分离。使领域层代码纯粹表达业务概念和业务规则,将具体...

    DDD:域驱动设计是一种软件开发方法,其中利用了与面向对象编程相关的概念和良好实践

    域驱动的设计:解决软件核心问题的复杂性-Eric Evans 实施域驱动设计-Vaughn Vernon 测验 [ TestClass ] public class Tests { [ TestMethod ] public void Email () { Assert . IsTrue ( new Email ( " domain...

    cargotracker:该项目演示了如何使用广泛采用的架构最佳实践(例如域驱动设计(DDD))使用Jakarta EE开发应用程序

    Eclipse货物追踪器-Jakarta EE的应用领域驱动设计蓝图 概述 该项目演示了如何使用广泛采用的体系结构最佳实践(例如域驱动设计(DDD))来使用Jakarta EE开发应用程序。 该项目直接基于DDD先驱Eric Evans的Domain ...

Global site tag (gtag.js) - Google Analytics