领域驱动设计和开发实战-住房贷款处理系统

本文先阐述领域驱动设计的基本概念,然后以住房贷款系统的需求为引线,一步一步实战讲解如何进行领域驱动设计的开发,文章来源与网上,先贴出与大家一起分享。
李锡远
2010-8-20

 

背景

驱动设计(DDD)的中心内容是如何将业务领域概念映射到件工件中。大部分于此主的著作和文章都以Eric Evans的驱动设计,主要从概念和设计的角度探讨领域建模和设计情况。些著作讨论实体、值对象、服等DDD的主要内容,或者谈论通用、界定的上下文(Bounded Context)和防护层(Anti-Corruption Layer)些的概念。

本文旨在从践的角度探讨领域建模和设计及如何着手域模型并实际实现它。我将着眼于技主管和架构实现过程中能用到的指、最佳践、框架及工具。驱动设计开发也受一些架构、设计实现方面的影响,比如:

 

  • 1、业务规则
  • 2、持久化
  • 3、缓
  • 4、事管理
  • 5、安全
  • 6、代生成
  • 7、测试驱动开发
  • 8、重构

 

本文讨论这些不同的因素在施的整个生命周期中怎样对生影响,有架构实现成功的DDD中应该求什。我会先列出域模型应该的典型特征,以及何在企中使用域模型(相于根本不使用域模型,或使用血的域模型来)。

文章包括一个理示例用,来演示如何将设计、以及讨论开发最佳践,用在真驱动开发项目之中。示例用用了一些框架去 现贷域模型,比如Spring、Dozer、Spring Security、JAXB、Arid POJOs和Spring Dynamic Modules。示例代用Java写,但大多数开发,不论语言背景如何,代都是很容易理解的。

 

引言

 

域模型来了一些好,其中有:

  • 1、有助于团队创建一个业务IT都能理解的通用模型,并用模型来沟通业务需求、数据体、程模型。
  • 2、模型是模化、可展、易于维护的,同时设计还反映了业务模型。
  • 3、提高了业务领象的可重用性和可性。

来,如果IT团队开发大中型企业软不遵循域模型方法,我看看会生些什

 

不投放源去建立和开发领域模型,会用架构出肥服务层和“血的域模型”,在这样的架构中,外观类(通常是无状Bean聚越 来越多的业务逻辑,而只有getter和setter方法的数据体。这种做法域特定业务逻辑规则散布于多个的外观类中(有些 情况下会出逻辑)。

 

在大多数情况下,血的域模型没有成本效益;它不会公司来超越其它公司的优势,因这种架构里要实现业务需求更,开发并部署到生产环境中去要花时间

 

在考DDD实现目中各架构和设计因素之前,先看看富域模型的特性:

  • 1、领域模型应该侧重于具体的业务操作域。它应该结业务模型、策略和业务流程。
  • 2、它应该业务中的其它域,用架构中的其它隔离来。
  • 3、它应该可重用,以避免相同的核心业务领域元素有任何重的模型和实现
  • 4、模型应该设计得与用中的其它松耦合,意味着与上下两(即数据和外观类)都没有依赖关系。
  • 5、它当是一个抽象的、清晰划分的次,以使维护测试、版本理更容易。可在容器外(从IDE中)对领类进测试
  • 6、它应该POJO程模型来设计,没有任何技或框架依性(我是告公司里我工作的团队,我们软开发用的技Java)。
  • 7、领域模型应该独立于持久化实现细节(尽管技模型有一些限制)。
  • 8、它应该最小程度地依于任何基础设施框架,因它将比些框架更久,我也不希望与任何外部框架耦合。

 

实现软开发中更高的投率(ROI),业务单位和IT的高管理人业务领域建模及其实现的投上(时间、金源)全力以赴。来看看实现领域模型需要的其它因素。

 

  • 1、团队应该经常接近业务领域主题专家。
  • 2、IT团队(建模者、架构开发良好的建模、设计技能。
  • 3、分析师应该具有良好的业务流程建模技能。
  • 4、架构开发员应该有丰富的面向设计OOD)和程(OOP经验

驱动设计在企架构中的作用

域建模和DDD在企架构(EA)中发挥着重要的作用。因EA的目之一就是合IT和业务业务实体的代表——域模型就是EA的核心部分。就是大多数EA件(业务或基础设施)应该围绕领域模型设计实现的原因。

 

驱动设计SOA

 

面向服的体系架构(SOA)最近帮助团队构建基于业务流程的件构件和服、加速新品上市时间势头越来越强劲驱动设计是SOA的一个关键因素,因它有助于封装象中的业务逻辑规则域模型也提供了定使用的言和上下文。

 

如果没有域模型,SOA的行就应该包括域模型的设计实现。如果我过强调SOA、忽略了域模型的重要性,那我用架构中最得到的就是一个血的域模型和臃的服

 

理想的情况是,在开发应和SOA件的同,迭代地实现DDD,因为应和SOA件都是域模型要素的直接消者。使用丰富的实现,通 过给领象提供一个壳(代理),SOA设计得相对简单。但如果我注SOA,在后端却没有一个像域模型,业务就会用不完整的域模 型,可能会致出一个脆弱的SOA架构。

 

目管理

 

域建模目通常包括以下步骤

  • 首先为业务流程建模并文档化。
  • 选择一个候业务流程,与业务领家一起使用通用言来文档化业务流程。
  • 识别选业务流程需要的所有服些服上可以是原子的(单步的)或合好的(多的,有无工作流皆可)。它也可以是业务(比如承保或金)或基础设施(比如件或工作度)。
  • 上一步识别的服所使用的象,确定并文档化其状和行

业务领域核心元素的候,就将模型保持在高水平是非常重要的。

 

目管理的点来看,真的DDD实现项目和其它开发项目所包含的段是一的。段包括:

  • 对领行建模
  • 设计
  • 开发
  • 测试和集成测试
  • 基于设计开发来完善、重构域模型(模型概念的持集成(CI))。
  • 使用更新的域模型重上述步骤实现CI)。

非常适合在里使用敏捷开发方法学,因敏捷方法注重于交付商,恰好DDD重于件系业务模型。此外,就DDD迭代的特性来 ,SCRUM或DSDM这样的敏捷方法对项目管理来也是更好的框架。合使用SCRUM(适用于目管理)和XP(适用于开发)方法对处理 DDD实现项目来非常好。

 

DDD迭代周期的目管理模型如1所示。

1. DDD迭代周期

 

域建模可以驱动设计于如何实现领象模型,Ramnivas Laddad推荐如下的步骤。他强调要更重于域模型中的象,而不是服

 

  • 体和逻辑开始。
  • 不要一始就从服务层开始,只添加那些逻辑不属于任何体或值对象的服
  • 利用通用言、设计(DbC)、自测试CI和重构,使实现尽可能地与域模型合。

设计实现的角度来看,典型的DDD框架应该支持以下特征。

 

  • 应该是一个以POJO(如果你的公司以.Net,就是POCO的架构。
  • 应该支持使用DDD概念的业务领域模型的设计实现
  • 应该支持像依注入(DI)和面向方向程(AOP些概念的箱即用。(注:稍后将在文章中详细释这些概念)。
  • 测试框架整合,比如JUnitTestNGUnitils等。
  • 与其它Java/Java EE框架行良好的集成,比如JPAHibernateTopLink等。

示例

 

本文中使用的示例用是一个住房理系业务用例是批准住房款(抵押)的金申。将款申提交抵押放公司的 候,首先要通承保程,承保人在程中根据客的收入情、信用记录和其它因素来决定批准是拒绝贷求。如果款申请获得承保的批准, 就批程序的清和融资步骤

 

理系中的融动给贷款人支付金。通常,融资过程从抵押放公司(通常是行)将款包给产权公司始。接着产权公司款包,并与房产买卖双方一起确定款的时间款人和方与算中介在产权公司会面、协议,来移房产产权

 

架构

 

典型的企业应用架构由下面四个概念上的层组成:

 

  • 界面(表现层):负责给展示信息,并解命令。
  • 该层协调应用程序的活。不包括任何业务逻辑,不保存业务对象的状,但能保存用程序任务过程的状
  • 包括业务领域的信息。业务对象的状里保存。业务对象的持久化和它的状可能会委托础设
  • 础设其它是一个支持性的。它提供的信息传递实现业务对象的持久化,包含界面的支持性等。

详细地看一下层。

 

  • 负责应用中UI屏幕之航,以及与其它系统应的交互。
  • 户输入的数据行基本(非业务)的验证,然后再把数用的其它(更底)。
  • 不包含任何业务域相逻辑、或数据访问逻辑
  • 没有任何反映商用例的状,但却能理用或任务进展的状

  • 负责业务领域的概念,业务用例和业务规则的相信息。象封装了业务实体的状和行用中的业务实体例子有抵押(Mortgage)、房Property)和款人(Borrower)。
  • 如果用例跨越多个用户请求(比如款登记过程包含多个步骤:用户输详细信息,系基于款特性返回品和利率,用户选择特定的/利率合,最后系会用利率款),可以管理业务用例的状(会)。
  • 包含服务对象,些服务对象只包含一个定好的、不属于任何象的可操作行。服封装了业务领域的状,而业务领域并不适用于象本身。
  • 是商业应用的核心,应该用的其它隔离来。而且,它不应该于其它使用的用框架(JSP/JSFStrutsEJBHibernateXMLBeans等)。

下面的2示了用中使用的不同架构次,以及它与DDD有怎系。

 

2. 层应用架构

 

下面的设计观点被认为是目前DDD实现诀窍的主要部分:

  • 面向程(OOP
  • 注入(DI
  • 面向方面程(AOP

OOP实现中最重要的基本原应该利用像承、封装和多态这样的OOP概念,使用Plain Java和接口来设计领象。大部分域元素是既有状(属性)又有行(操作状的方法或操作)的真正象。它时对应于真世界的概念,能很合 适地适用于OOP概念。DDD中的体和值对象都是OOP概念的典型例子,因有状和行

 

在典型的工作元(UOW)中,象需要与其它的作,无论这象是服是工厂。需要理其它那些本身就横切的 注点, 比如域状态变化跟踪、审计存、事管理(包括事)。些都是可重用、非域相注点,通常很容易在包括的整个代中散布和重。在 象中嵌入该逻辑和非域相的代互相纠缠生混乱。

 

之没有耦合的代赖关系和隔离横切注点的候,OOP并不能独自为领驱动设计开发提供极好的设计解决方案。在是可以利用DI和AOP这样设计概念OOP充,以尽量减少耦合、提高模化、更好地理横切注点。

 

注入

 

DI能很有效地将配置和依象中移出。此外,类对数据访问对象(DAO)、服务类对领设计性使得DI成DDD实现中“必有”的内容。通和服的其它象注入到象,DI有助于建一个更清晰、松耦合的设计

 

在示例用中,服务对象(FundingServiceImpl)利用DI注入象(LoanBorrowerFundingRequest)。体也通DI引用的,像数据源、Hibernate工厂管理器些其它的Java EE源也被注入到服库对象中。

 

面向方面

 

象中移除横切注点代,比如检查域状态变化跟踪等,AOP有助于实现一个更好的设计(即在域模型中少一些乱七八糟的内容)。可利用 AOP把象和服注入象,特是那些容器没有例化的象(比如持久化象)。在可以利用AOP的中,其它的方面有存、事管理和基 于角色的安全(授)。

 

用利用自定方面将数据存引入服务对象。品和利率信息从数据表中加一次(客端第一次些信息),然后存到适用于后面品和利率找的存(JBossCache)中。品和利率会被访问,但不会定期更新,所以存数据是一个很好的候方案,而不是次都从后端的数据库获取。

 

在近期的讨论贴子里,DDD中DI和AOP概念的作用是主要的话题讨论以Ramnivas Laddad的演讲为,Ramnivas在其演中主没有AOP和DI的帮助,DDD无法实现。 Ramnivas在个演讨论了“粒度DI”的概念,一概念利用AOP使象恢机敏性。他说领象需要访问其它粒度的象来提供丰富的 行该问题的解决方案是在象中注入服、工厂或(通用构造或setter方法期使用方面来注入依)。

 

Chris Richardson讨论了有利用DI象和方面,通减少耦合、提高模化来改进应设计。Chris到了“超大服反模式,用代耦合、混乱、分散的果,他还谈了如何利用DI和AOP的概念来避免一反模式。

 

注解

 

最近定理方面和DI的趋势是使用注解。对实现远程服(比如EJB或Web Services)来,注解有助于减少所需的工件。它们还简化了配置管理任Spring 2.5Hibernate 3,以及其它框架都充分利用注解在Java业应用的不同中配置件。

 

们应该利用注解生成模板代,模板代能在灵活性上增加价但同时应该谨慎使用注解。注解应该用于不会引起混淆或实际的地方。使用注解 的一个很好的例子是Hibernate ORM映射,注解能直接用或属性名指定的SQL表或列名添加。另一方面,像JDBC驱动配置(驱动类名、JDBC URL、用名和密这样详细信息更适合于存放在XML文件中,而不是使用注解。基于数据在同一个上下文中一假。如果域模型和数据表之 需要相当多的转换,那就应该好好思考一下设计了。

 

Java EE 5提供JPA注解,比如@Entity@PersistenceUnit@PersistenceContext等,以此给简单Java添加持久化细节域建模上下文中,体、和服都是使用注解的好地方。

@Configurable是 Spring将和服注入象的方式。Spring框架在@Configurable注解之上展了“象依注入”思想。 Ramnivas最近在博客中谈论了即将布的Spring 2.5.2版本(从目的Snapshot Build 379始可用)的最新改进。 有三个新的方面(AnnotationBeanConfigurerAspect AbstractInterfaceDrivenDependencyInjectionAspect AbstractDependencyInjectionAspect为领象依注入提供了简单、更灵活的选择Ramnivas,引入中的方 面(AbstractInterfaceDrivenDependencyInjectionAspect),其主要原因是要让领域特定的注解和接口发挥 作用。Spring提供了其它注解来帮助设计领象,比如@Repository@Service@Transactional

 

示例用中使用了部分注解。象(Loan、Borrower和FundingRequest)使用了@Entity注解;使用@Configurable注解库对象;服务类也使用@Transactional注解来用事方法。

 

域模型和安全

 

用安全确保只有授的客端(人或其它用)能域操作,访问领域状

 

Spring安全(Spring Portfolio的一个子目)同时为应用的表现层(以URL)和(方法)提供了粒度的访问控制。框架使用Spring的Bean Proxy来截方法用,运用安全束。它使用MethodSecurityInterceptor的Java象提供了基于角色的声明式安全。它也有针对领象的访问控制列表(ACL's)形式的级别安全,以控制级别的用户访问

 

域模型中使用Spring安全来理授需求的主要好是,框架有一个非侵入式的架构,我可以完全隔离域和安全方面。此外,业务对象也不会和安全实现细节混成一。我可以只在一个地方写通用的安全规则,(使用AOP技)在任何需要实现的地方运用它

 

域和服务类中,授方法级别进理。例来于高达一百万美元的款,承保象中的“批”方法可以由任何具有“承保 人”角色 的用户调用;而于超一百万美元的款申,同一象中的批方法只能由具有“核保主管”角色的用户调用。

 

下表明了用架构用的各安全注点。

表1. 各个中的安全注点

安全注点

/控制器

认证Web面(URL)界

基于角色的授

级别ACL

数据

DB级别(存储过程、存函数、触器)

业务规则

 

业务规则业务领域中的重要部分。它了数据验证和其它的规则规则需要用于特定业务流程景中的象。业务规则通常分下面几

  • 数据验证
  • 数据转换
  • 决策
  • 流程流向(工作流逻辑

上下文在DDD世界中非常重要。上下文的特性决定了作及其它运行因素,比如运用什么业务规则等。验证以及其它业务规则往往都是在一个特 定的 上下文中理的。意味着,相同的象在不同的业务上下文中将不得不理不同的一组业务规则。比如,通批流程中的承保步骤后,象的一些属性(像款数和利率)就不能再改了。但在刚刚并与特定利率关联候,同的属性是可以改的。

 

尽管所有的域特 定业务规则应该封装在,但一些设计规则放在了外观类中,这导致了业务规则逻辑方面成了“血的”。在小型用中可能是可接受的 解决方案,但不推荐将其用于包含复杂业务规则的中大型企业应用。更好的设计方案是把规则放在它们应该在的地方——象中。如果一个业务规则 跨越两个或两个以上的象,那么该规则应该务类的一部分。

 

此外,如果我不在用中下苦功,往往把业务规则变成代里的一串switch句。随着规则变得越来越复杂开发不会愿意花费时间去重构代 ,将 switch句移到更易于管理的设计中。在中硬编码复杂的流向或决策规则逻辑中出的方法、代、最僵化的设计长远来看, 将成为维护的噩梦。一个良好的设计是把所有的规则(特是随着业务策略的化而繁改复杂规则)放到规则引擎(利用规则框架,比如JBoss RulesOpenRulesMandarax)中去,并从用。

 

验证规则通常会用不同的实现,比如Javascript、XML、Java代有其它脚本言。但由于业务规则动态特性,RubyGroovy域特定(DSL) 些脚本言是定、管理规则更好的选择。Struts()、Spring(服务层)和Hibernate(ORM)都有其自己的验证,我 可以在验证对传入或出的数据象运用验证规则。在一些情况下,验证规则还能被方面,它可以合到用的不同次中去(比如服和控 制器)。

 

类处业务规则时紧记单测试方面是非常重要的。规则逻辑中的任何化都应该很容易、独立地元可

 

示例用包括一个业务规则集来验证贷款特性是否都在允品和利率格内。规则在脚本言中(Groovy)行定,并用于传递给FundingService象的款数据。

 

设计

 

设计的角度出层应该有一个定清晰的界,以避免来自非核心层关注点的坏,比如特定供商的明、数据过滤转换等。域元素 应该设 计为正确地保存域状和行。不同的域元素会基于状和行为进行不同的构化。下面的表2展示了域元素及其包含的内容。

 

表2. 域元素及其状和行

域元素

/

体、值对象、聚合

和行都有

数据传输对

只有状

只有行

 

包含状(数据)和行(操作)的体、值对象、聚合应该有定清晰的状和行。同应该超出界的范应该在作用于本地状的用例中完成大部分工作。但它应该知道太多无的概念。

那些封装象状所需要的属性来,好的设计实践是只包括些属性的getter/setter方法。设计领,只那些能改的属性提供setter方法。此外,公有的构造函数应该只含有必需的属性,而不是包含中所有的属性。

 

在大部分用例中,我并不是真的要去直接改变对象的状。所以,代替改内部状的做法是,建一个有已改的新象并返回象。这种方法在些用例中就足了,能降低设计复杂性。

聚合类对调用者藏了的用法。聚合可用来封装复杂的、有侵入性的、状的需求。

 

支持DDD的设计模式

 

有几有助于驱动设计开发设计模式。下面是设计模式的列表:

  • 象(DO
  • 数据传输对象(DTO
  • DTO装器
  • 包含中心的方法,并使用DAO与数据交互。
  • 泛型DAO
  • 时态模式(Temporal Patterns):些模式丰富的域模型添加了时间维Bitemporal框架基于Martin Fowler时态模式为处域模型中的双时态问题提供了设计方法。核心的象及其双时态属性能用ORM品持久化,比如Hibernate

在DDD中用的其它设计模式包括策略模式、外模式和工厂模式。Jimmy Nilsson在他的讨论了工厂模式,认为它是一种领域模式。

 

DDD反模式

 

在最佳践和设计模式的反面,架构开发实现领域模型时还应该提防一些DDD的坏气味。由于些反模式,用架构中成最不重要的部分,外观类反而在模型中承担了更重要的任。下面是一些反模式:

  • 血的
  • DAO
  • 肥服务层:服务类里最会包含所有的业务逻辑
  • 依恋情Feature Envy):Martin Fowler在他于重构的中提到的典型的坏气味,在反模式中,一个的方法属于其它的数据太念念不忘。

数据访问对

 

DAO驱动设计中都很重要。DAO是系型数据用之的契。它封装了Web用中的数据CRUD操作细节。另一方面,是一个独立的抽象,它与DAO行交互,并提供到域模型的“业务接口”。

使用域的通用言,理所有必要的DAO,并使用域理解的言提供对领域模型的数据访问

 

DAO方法是粒度的,更接近数据,而方法的粒度粗一些,而且更接近域。此外,一个库类中能注入多个DAO。和DAO能防止解耦的域模型去理数据访问和持久化细节

 

应该只依接口。就是是注入、而不是DAO会生一个更规则域模型的原因。DAO不能由客端(服和其它的消)直接用。客应该终调象,象再用DAO将数据持久化到数据存中。

 

象之的依赖关系(比如体及其的依赖关系)是开发员经常遇到的典型问题。解决问题通常的设计方案是务类或外观类直 接,在候返回端。该设计终导致前面提到的域模型,其中外观类始堆更多的业务逻辑,而为单纯的 数据体。好的设计是利用DI和AOP技和服注入到象中去。

 

示例用在实现贷域模型遵循了设计

 

持久化

 

持久化是一个基础设施方面,层应该与其解耦。JPA通过对类隐藏持久化实现细节,提供了一抽象。它由注解推,所以不需要XML映射文件。但同,表名和列名嵌在代中,在某些情况下可能并不是一个灵活的解决法。

使用提供数据网格解决方案的网格品,比如OracleCoherenceWebSphereObject GridGigaSpaces开发在建模和设计业务领,完全不需要考RDBMS。数据库层用内存/数据网格的形式从抽象出来。

 

 

在我们讨论领的状(数据),我不得不问题访问域数据(比如抵押用中的品和利率)很存起来。存能提高性能,减少数据器的负载。服务层很适合域状TopLinkHibernate些ORM框架也提供数据存。

 

理示例用使用JBossCache框架来品和利率情,以减少数据库调用、提高用性能。

 

管理

 

保持数据完整性、整体提交或回UOW(工作元模式)来,事管理是很重要的。应该用架构的哪里理事一直存在争。交叉体的事(在同一UOW中跨越多个象)也影响在哪里理事务这设计决策。

一些开发员倾向于在DAO中管理事是一个欠佳的设计该设计导过细粒度的事控制,那些事跨越多个象的用例来这种控 制没有 灵活性。服务类应该处理事;即使事跨越多个象,服务类也能理事,因在大多数用例中,是服务类理控制流。

 

示例用中的FundingServiceImpl类处金申的事,通过调库执行多个数据操作,并在一事中提交或回所有的数据库变化。

 

数据传输对

 

象模型在构上与从业务接收或送的消息不兼容,在这样SOA境中,DTO就是设计中很重要的一部分。消息通常都在XML模式定 文档 (XSD)中定维护,从XSD写(或代生成)DTO象,并在域和SOA服务层使用它传输数据(消息)是一普遍的做法。在分布式用 中,将来自于一个或多个象中的数据映射到DTO中会成必然的弊端,因从性能和安全角度出,跨越网络发象是不实际的。

 

从DDD的角度来看,DTO有利于维护务层和UI隙,其中DO用于和服务层,DTO用于表现层

 

Dozer框架用于将一或多个一个DTO象。它是双向的,将转换为DTO候,它会保存大量用的代限,反之亦然。DO和DTO之的双向映射有利于消除“DO到DTO”和“DTO到DO”各自的转换逻辑框架能正确型和数转换

 

示例用在理申到来,利用Dozer映射文件(XML)将FundingRequestDTO象划分成Loan、Borrower、 FundingRequest象。在返回,映射同样负责将来自体的金响数据聚合到一的DTO象中。

 

DDD实现框架

 

SpringReal Object OrientedROO)、HibernateDozer些框架都有助于设计实现领域模型。支持DDD实现的其它框架有Naked ObjectsRuby On RailsGrails,以及Spring Modules XT Framework

Spring负责实例化,并将服、工厂和库这类联接在一起。它使用@Configurable注解将服注入体。注解是Spring特有的,所以完成一注入的其它选择是使用如Hibernate截器的西。

ROO是建立在点“域第一,基础设施第二”之上的DDD实现框架。开发该框架是了减少Web开发中模式的模板编码。利用ROO,我义领域模型,接着框架(基于Maven Archetypes模型-视图-控制器(MVC)、DTO、业务层和DAO生成代。它也能为单测试和集成测试生成stubs。 

 

ROO有几个非常用的实现模式。比如,它区分理属性的状、使用属性级访问的持久、只反映必需属性的公有构造函数。

 

开发

 

没有实际实现,模型就没有用实现阶应该尽可能多地自化完成开发了看看什能自完成,看看域模型的一个典型用例。下面是用例的步骤列表:

求:

  • 用外观类,以XML文档(XSD兼容的)的方式送数据;外观类为UOW初始化一个新的事
  • 验证输入的数据。验证包括基本验证(基本的/数据/属性级检查)和业务验证。如果有任何的验证错误,抛出适当的异常。
  • 将描述转换为(以成为简单域)。
  • 数据格式,以成为简单域模型。
  • 行所有的属性分割(比如,在客户实象中,将客姓名分成名字和姓)。
  • 把DTO拆分一或多个象。
  • 持久化象的状

出响

  • 从数据存象的状
  • 如果必要,存状
  • 为对应用有利的数据象(DTO)。
  • 行所有的数据元素合并或分离(比如合名字和姓,一的客姓名属性)。
  • 将代码转换为描述。
  • 必要数据格式,以理客端数据使用的要求。
  • 如果有必要,DTO的状
  • 提交(如果有错误则),退出控制流。

下表示了用中不同的象,象将一个的数据到另一个

3. 层间的数据流向

起点

框架

DAO

数据

DO

Hibernate

域委托     

DO

DTO

Dozer

数据传输

DTO

XML

JAXB

正如你所看到的,相同的数据以不同形式(DO、DTO、XML等)在用架构中传递并不多。大部分持有数据的象(Java或XML), 有像 DAO、DAOImpl、DAOTest类实际上都是基础设施。些有模板代构的、XML文件都很适合代生成。

 

生成

 

ROO这样的框架还为建了一个准、一致的目模板(使用Maven插件)。使用先生成的目模板,我可以实现录结构的一致性,其中存放源测试类、配置文件,以及内部和外部(第三方)的依赖关系。

典型的企业软用所需的种种类和配置文件,其数量之多令人望而生畏。代生成是解决该问题的最好法。代生成工具通常使用某模板框架来定模板,或是代生成器能从中生成代的映射。Eclipse建模框架(EMF)的几个子目有助于Web目需要的各工件的代生成。模型驱动架构(MDA)工具,比如AndroMDA,都利用EMF在架构模型的基上生成代

到在层编写委托,我看到开发动编(大多是从无到有地写完第一个,接着用“制并粘的模式来其它的建所需的委 托 )。由于大部分都是的外,它很适合代生成。代生成是长远的解决法,尽管建立并测试生成器(引擎)增加了初期的投入(代量和 时间)。

生成的测试类,一个好的选择就是在需要测试的主中,为带复杂业务逻辑的方法建抽象方法。这样开发承生成的测试,然后实现不能自生成的自定义业务逻辑。同个方法也适用于任何有不能自动创测试逻辑测试方法。

对编写代生成器来,脚本言是一个更好的选择,因们开销少,支持模板建和自定义选项。如果我在DDD目中充分利用代生成,我只需要从无到有地写少量的代从无到有建的工件有:

  • XSD

一旦我了XSD和Java,我可以生成下列全部或大部分的和配置文件:

  • DAO接口和实现类
  • 工厂
  • 域代理(如果有必要)
  • (包括EJBWebService
  • DTO
  • 上述测试(包括测试类测试数据)
  • Spring配置文件

表4列出了Web用架构中不同的,以及那些中能生成什工件(Java或XML文件)。

表4. DDD实现项目中的代生成

/功能

模式

你写的代

生成的代

框架

数据访问

DAO/

  

DAO接口,
DAO实现类
DAOTest
测试种子数据

Unitils,
DBUnit

DO

DomainTest

  

持久化

ORM

ORM映射,
ORM映射测试

Hibernate,
ORMUnit

数据传输

DTO

XSD

DTO

JAXB

DTO

映射

DO-DTO映射文件

Dozer

委托

业务委托     

DO到DTO的转换

  

  

  

  

程服
EJB,
Web Service

控制器

MVC

控制器映射文件

Struts/Spring MVC

  

表示

MVC

视图配置文件

Spring MVC

  

委托是唯一同理解象和DTO的。其它,例如持久,不应该到DTO。

 

重构

 

重构就是改用代,但不修改用的功能或行。重构可以是设计的,也可以是代的。设计重构是了不断完善模型、重构代来提升域模型。

由于重构的迭代性和域建模不断演的性,重构在DDD目中发挥着重要作用。将重构任集成到目中的方法之一是在目的次迭代中添加重构环节,重构束之后才算完成迭代。理想情况下,每项开发之前和之后都应该进行重构。

 

行重构应该格的定。合使用重构、CI和测试,以确保代码变化不会破坏任何功能,同,代化要有助于以后的代和性能改

测试在重构用代发挥着至重要的作用。没有良好的自测试测试驱动开发(TDD)践,重构可能会生反面的效果,因没有自化的方式去验证重构一部分的设计和代化没有改、或破坏功能。

 

Eclipse 的工具有助于用迭代的方式和作为开发一部分的重构来实现领域模型。Eclipse有一些功能,比如把一个方法提取或移到不同的中,或将一个方法下推 到子中。也有几个Eclipse代分析插件有助于理代赖关系、识别DDD反模式。我做目的设计和代码审查时,都是依靠插件JDependClassycleMetrics用中域和其它模量。

Chris Richardson运用代重构,以使用Eclipse提供的重构功能将设计转变为一个OO设计

 

测试/集成

 

们刚到的目之一是类应该(在最初的开发阶段,以及随后重构已有代码时元可,而不多依于容器或其它基础设施代。TDD方法有 助于 尽早地找出任何设计问题,并有助于验证域模型在保持一致。DDD对测试先行开发是很理想的,因和行都包含在中,而且测试们应该是容易的。测试领域模型的状和行,又不太过关注于数据访问或持久化的实现细节是很重要的。

测试框架,比如JUnit或TestNG,都是实现域模型很棒的工具。其它测试框架,像DBUnit和Unitils,也可用来测试领,尤其是把测试数据注入到DAO中。测试类中增加测试数据来将大大减少外的代

 

拟对象(Mock objects)同有利于测试领象。但是在不要用模拟对象是很重要的。如果有其他测试领简单方法,你应该使用些方法来代替使用 模拟对象。比如,如果你能使用真的后端DAO(而不是模的DAO实现)和内存HSQL数据(而不是真的数据测试一个,能使层单测试运行得更快,而运行得更快正好是使用模拟对象潜在的主要想法。这样,你将能测试领象之作(交互),以及它的状(数据)。使用 模拟对象,我们则只能测试领象之的交互。

 

一旦开发完成,所有在开发阶建的测试和集成测试(不管有没有使用TDD做法)都将成测试套件的一部分。测试应该经维护,并常在本地或更高一开发环境中行,以便找出新的代码变化是否在中引入了Bug。

 

Eric Evans在他的中提到了CI,他CI应该运用在界定的上下文中,应该包括人和代的同。像CruiseControlHudson些CI工具可用来建立一个自化构建和测试境,来运行用构建脚本(使用Ant或Maven些构建工具建)从SCM仓库中(像CVSSubversion等)出代编译领(以及用中的其它),并在没有构建错误的情况下自运行所有的测试测试和集成测试)。CI工具可以置在有任何构建或测试错误时(通E-mail或RSS Feeds)通知团队

 

部署

 

域模型绝对不会是静的;在目生命周期中,它会随着业务需求的演、新目中新需求的提出而化。此外,随着你开发实现领域模型,你能不断学和提高,而且你也想在已有的模型中运用新的知

打包、部署候,隔离很关键。因为领于DAO的一面,而服观层又依于DAO的另一面(参见图2-用架构),所以打包、部署一或多个模理依赖关系很有意

DI、AOP和工厂设计模式在设计阶段减少了象之的耦合,并使用模化;OSGi(以前被称为开放服关规范)在运行时处理模化。OSGi正在成打包、布企业应用的准机制。它能很好地理模的依赖关系。我们还能用OSGi来域模型的版本理。

 

可以把DAO打包到一个OSGi的Bundle(DAO Bundle)中,把服观类打包到另一个Bundle(服Bundle)中,所以DAO或服务实现进行了修改,或是部署了用的不同版本,由于 OSGi,用都不需要重启。如果我们为了向后兼容,必支持某些象已有的版本和新的版本,那我也可以部署相同的两个不同版本。

 

了利用OSGi的能力,象在消之前(即在客端能找到它之前),应该在OSGi平台中行注册。意味着我使用OSGi的API行注册,我们还须处理使用OSGi容器启和通知服务时的失败场景。Spring Dynamic Modules框架对该领域很有利,它允用中出或入任何型,而不改任何代

 

Spring DM提供测试类,以在容器外运行OSGi集成测试。比如,能从IDE中直接用AbstractOsgiTests运行集成测试置由测试础设施来理,所以我不需要为测试编写MANIFEST.MF文件,或者行任何的打包或部署。框架支持大部分目前可用的OSGi实现EquinoxKnopflerfishApache Felix)。

 

用使用OSGi、Spring DM、Equinox容器来理模块级别的依赖关系,以及域和其它模的部署。LoanAppDeploymentTests明了Spring DM测试的用法。

 

示例设计

 

理示例用中用到的如下:

体:

  • Loan
  • Borrower
  • UnderwritingDecision
  • FundingRequest

值对象:

  • ProductRate
  • State

  • FundingService

  • LoanRepository
  • BorrowerRepository
  • FundingRepository

3展示了示例用的域模型

3. 层应域模型

 

在本文中讨论的大部分DDD设计概念和技都在示例用中行了运用。像DI、AOP、注解、级别安全、持久化些概念都用到了。另外,我使用了几个源框架来助力DDD开发实现些框架列如下:

  • Spring
  • Dozer
  • Spring安全
  • JAXB(用于封送理和取消封送理数据的Spring-WS
  • Spring Testing(用于测试和集成测试
  • DBUnit
  • Spring Dynamic Modules

示例用中的利用Equinox和Spring DM框架部署OSGi。下表示了示例用的模打包细节

5. 打包、部署细节

部署工件名称

内容

Spring配置文件

/控制器

loanapp-controller.jar

控制器,客端代理

LoanAppContext-Controller.xml

loanapp-service.jar

程)服,服代理XSD

LoanAppContext-RemoteServices.xml

loanapp-domain.jar

DAO,通用的DTO

LoanAppContext-Domain.xml, LoanAppContext-Persistence.xml

框架

loanapp-framework.jar

框架,用工具,监视JMX,方面

LoanAppContext-Framework.xml, LoanAppContext-Monitoring.xml, LoanApp-Aspects.xml

结论

 

DDD是一个功能大的概念,只要团队接受了DDD的培,并始运用“域第一,基础设施第二”的点,它就会改建模者、架构开发 思考件的方式。由于域建模、设计实现中会及具有不同背景和专长领域的不同利益相方(来自IT和业务单位),引用Eric Evans的法,“不要弄混设计观点(DDD)和有助于我完成它的技工具箱(OOP、DI、AOP)之的界限”。

 

中的新

 

涵盖了一些新出的、影响DDD设计开发的方法。些概念中的一些仍在不断展,察它将如何影响DDD也很有意思。

 

域模型准的治理、策略施,以及实现的最佳践中,施Architecture Rules和契设计起到了重要作用。Ramnivas到了利用Aspects来工厂库对象;是在设计领层时经常被背的规则

域特定言(DSL)和业务自然言(BNL)近几年来正得到越来越多的注。人可以在中使用言表达业务逻辑。BNL可以用来保存 业务规 范,记录业务规则能作行代,从这种上来,BNL是非常大的。能用它们创测试用例,来验证是否如期的那

 

为驱动开发(BDD) 是最近被讨论的另一个有趣概念。通提供跨越业务和技间鸿沟的通用词汇(通用言),BDD有利于将开发集中在有先次序、可验证的商布 上。通利用重于系方面的术语,而不是单单着眼于测试,BDD引导开发将TDD背后的真正价最大程度地发挥出来。如果正确践的,BDD 可以成DDD很好的充,BDD概念会对领象的开发产极的影响;象就是和行的封装。

 

事件驱动的体系架构(EDA) 是能在驱动设计发挥作用的另一个域。比如,在例中通知任何状态变化的事件模型将有助于理后事件(post-event)理任, 在象的状变时,后事件理任就需要被触。EDA有利于封装基于事件的逻辑,将之嵌进领逻辑的核心。Martin Fowler述了领域事件设计模式。

 

 

posted @ 2010-08-20 22:55  远哥  阅读(1928)  评论(1编辑  收藏  举报