`

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

阅读更多

  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是告诉我们如何做好业务层!并以领域驱动设计思想来选择和合适的框架,本文以基于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集合。

失血模型

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

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

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

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

分享到:
评论

相关推荐

    Domain-Driven Design: Tackling Complexty in the Heart of Software -- 领域驱动设计: 软件核心复杂性应对之道》

    关于DDD可参考InfoQ的Mini Book Domain Driven Design Quickly , 还有 Banq 的文章 实战DDD(Domain-Driven Design领域驱动设计), 和 领域模型驱动设计(DDD)之模型提炼 。 本书分为四部分,第一部分讲述了领域模型...

    Domain-Driven Design领域驱动设计

    领域驱动设计(Domain-Driven Design,简称DDD)是一种处理复杂软件核心问题的方法,由Eric Evans在其2002年的著作中首次系统阐述。DDD是一种综合性的设计理念,它强调将软件开发的焦点放在业务领域,并围绕业务领域...

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

    领域驱动设计(Domain-Driven Design,简称DDD)是一种软件开发的方法论,它由Eric Evans在其2004年的同名书籍《领域驱动设计:软件核心复杂性应对之道》中提出。DDD的核心思想是,软件系统的复杂性不仅仅是由技术...

    Domain-Driven-Design-Distilled.zip

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

    .NET Domain-driven design with C# 源码 chapter 2

    .NET框架与C#语言结合应用领域驱动设计(Domain-driven Design, DDD)是现代软件开发中的一个重要实践。DDD旨在通过将复杂的业务逻辑集中在核心领域模型上,提高软件系统的可读性、可维护性和可扩展性。本章节我们将...

    Domain-Driven Design –Tackling Complexity in the Heart of Software.pdf

    The software development community widely acknowledges that domain modeling is central to software design. Through domain modeling, software developers are able to express rich functionality and ...

    Domain-Driven Design Distilled

    《领域驱动设计精粹》(Domain-Driven Design Distilled)是Vaughn Vernon所著的一本关于领域驱动设计(Domain-Driven Design,简称DDD)的入门指南。DDD是一种软件开发的方法论,它强调在软件开发过程中,开发者...

    Domain-Driven Design Complexity In Software.pdf

    ### 域驱动设计(Domain-Driven Design, DDD):应对软件核心复杂性 #### 概述 《域驱动设计:应对软件核心复杂性》一书由埃里克·埃文斯(Eric Evans)撰写,Addison Wesley出版社于2003年8月20日出版。该书共560...

    JavaScript Domain-Driven Design(PACKT,2015)

    JavaScript Domain-Driven Design allows you to leverage your JavaScript skills to create advanced applications. You'll start with learning domain-driven concepts and working with UML diagrams. You'll ...

    Domain+Driven+Design 领域驱动设计

    领域驱动设计(Domain-Driven Design,简称DDD)是由Eric Evans在其2003年的同名书籍中首次提出的软件开发方法论。该方法论的核心思想是将软件开发的焦点集中在业务领域模型上,强调软件系统与现实世界业务领域的...

    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...

    Patterns, Principles And Practices Of Domain-driven Design

    域驱动设计(Domain-Driven Design, DDD)是一种面向对象的设计方法,它强调的是从业务领域出发,将业务需求和规则转换为软件模型。DDD认为,一个好的软件系统应该是基于对业务领域的深刻理解而构建的,并且能够随着...

    Domain-driven design

    领域驱动设计(DDD)是一种软件开发方法,由Eric Evans在其同名著作《领域驱动设计:软件核心复杂性应对之道》中提出。DDD的核心思想是通过深入理解和表达业务领域的复杂性来构建高质量的软件系统。这种方法强调了将...

    领域驱动设计模式、原理与实践[英文版]

    Millett S., Tune N. - Patterns, Principles, and Practices of Domain-Driven Design (Programmer to Programmer) - 2015.pdf

Global site tag (gtag.js) - Google Analytics