`
ahuaxuan
  • 浏览: 638068 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

这是半年前翻译的pojos in action,之前发在其他的blog,现在搬过来(第一部分)

阅读更多
 

      pojos in action

第三章   使用领域模型模式

<o:p> </o:p>

<o:p> </o:p>

当开发者发现了新的更好的途径来开发应用程序的时候,编程语言和技术也随之发展了。在上世纪九十年代的时候,用oo设计技术来解决复杂的应用程序是一种普遍被人接受的观点。然后,接下来的十年中ejb来了。在使用ejb之前的十年中,我用各种oo语言来开发程序,包括common lispc++java。但是oo设计在用ejb开发程序的时候就不是那么重要了,也和平时有很大的不一样了。然而许多早期的企业应用程序十相当复杂而且能从oo中受益的,正如我在第一章中所描述的那样,是文化和技术阻碍了我们使用这样策略。幸运的是,java技术已经发展了,而且把这些障碍物清除到一边了。当用pojo和轻量级框架开发的时候,你可以在你的企业应用程序中使用oo设计技术

<o:p> </o:p>

       这一章描述了领域模型模式,它可以把业务逻辑作为一个领域模型组织起来。一个领域模型是应用程序的问题领域的一个对象模型,它可以确定应用程序要解决的问题。领域模型模式是很重要的,因为它提供了oo开发的所有优点,包括提高可维护性和可扩展性。

<o:p> </o:p>

       在这一章中,你将学习到如何把一个领域模型融入到应用程序的框架中,领域模型的和表现层及持久层的关系。我也描述了领域模型的结构,及如何减弱来自数据库和其他外部组件的影响,从而可以使之更容易开发也更容易测试。你将学习到如何用tdd技术来开发一个pojo领域模型。在这一章中,我用place order的领域模型来作为示例。

<o:p> </o:p>

3.1 理解领域模型模式

<o:p> </o:p>

       领域模型模式用很早就流行的ooad技术来实现业务逻辑。这种模式用ooad来建立一个对象模型-领域模型-这两者都是问题领域的描述,而且都是业务逻辑设计的蓝图。一个对象模型由一些对应于问题领域概念的类组成,这样可以使之更容易理解。此外,如我前面提到的,一个对象模型是处理复杂业务逻辑的好方法。

<o:p> </o:p>

       用领域模型模式来实现业务逻辑在结构上和传统的ejb设计是有很大的不一样的。和业务逻辑被集中在少量的,体形很大的类中相比,领域模型由很多相关的小类组成,这些小类都具有状态和行为。比如说,在这章的后面一点,你将看到food to go这个程序中的领域模型由几个类组成,比如说OrderRestaurantMenuItem

<o:p> </o:p>

       在使用领域模型模式时的一个重要问题是如何访问数据库。许多领域模型类是能把相应的数据持久到数据库的。除非领域模型及其简单,否则应用程序必须使用一个orm持久化框架来把对象的信息保存到数据库。在4-6章中,你将会学到如何用hibernatejdo来持久化一个领域模型,这是两个流行的orm框架,在第10章,将会告诉你用ejb3来持久化一个领域模型。

<o:p> </o:p>

       现在让我们看一下一个领域模型是如何融入到一个全部的应用框架中的以及它于表现层及持久层框架的关系;在这之后,我们将会去探究一下领域模型的结构

<o:p> </o:p>

3.1.1 领域模型在何处融入到整体架构中

<o:p> </o:p>

       在一个业务对象由领域模型组织的应用程序中,领域模型是业务层的核心。考虑一下,比如说,下面所示的应用中,包括表现层,业务层,和一个持久化框架。正如这个图所示,领域模型被表现层调用,也被一个封装业务层的facade调用。

<o:p> </o:p>

       当直接或间接通过facade调用领域模型的时候,表现层处理从用户浏览器过来的http request,正如我在之前的章节描述的那样,这是个pojo或者一个ejb。每一个request都会导致一个或多个领域模型的方法被调用。这些方法执行多种业务逻辑操作,包括得到和确认数据,执行计算,并且更新数据库。

<o:p> </o:p>

       持久的领域对象不会知道他们是持久化的。他们明显的通过持久化框架映射到数据库。只有很少的领域模型类(这些类被称之为repositories,正如你后面将要看到)需要显式的调用持久化框架来执行创建,查询,删除持久对象。结果,我们可以开发几乎全部的领域模型而不需要担心持久化的问题。领域模型由pojo组成,而且调用持久化框架被隐藏在接口的后面。在下一章我们将从细节上来看看持久化的问题,但是现在,让我们来检查一下领域模型的结构。

<v:shapetype id="_x0000_t75" path="m@4@5l@4@11@9@11@9@5xe" o:preferrelative="t" filled="f" stroked="f" coordsize="21600,21600" o:spt="75"><v:stroke joinstyle="miter"></v:stroke><v:formulas><v:f eqn="if lineDrawn pixelLineWidth 0"></v:f><v:f eqn="sum @0 1 0"></v:f><v:f eqn="sum 0 0 @1"></v:f><v:f eqn="prod @2 1 2"></v:f><v:f eqn="prod @3 21600 pixelWidth"></v:f><v:f eqn="prod @3 21600 pixelHeight"></v:f><v:f eqn="sum @0 0 1"></v:f><v:f eqn="prod @6 1 2"></v:f><v:f eqn="prod @7 21600 pixelWidth"></v:f><v:f eqn="sum @8 21600 0"></v:f><v:f eqn="prod @7 21600 pixelHeight"></v:f><v:f eqn="sum @10 21600 0"></v:f></v:formulas><v:path o:connecttype="rect" o:extrusionok="f" gradientshapeok="t"></v:path><o:lock aspectratio="t" v:ext="edit"></o:lock></v:shapetype><v:shape id="_x0000_i1025" style="WIDTH: 6in; HEIGHT: 630pt" type="#_x0000_t75"><v:imagedata o:title="3" src="file:///C:\DOCUME~1\azhang\LOCALS~1\Temp\msohtml1\03\clip_image001.jpg"></v:imagedata></v:shape>

<o:p> </o:p>

3.1.2 领域模型的实例

<o:p> </o:p>

       一个领域模型由相互连接的对象网组成,他们中的许多都兼有状态和行为。如同存储数据一样,一个领域模型对象通常实现了对数据进行操作的业务逻辑。在典型的领域模型中的大多数类都具体的指向了应用程序的问题域。一个银行应用程序的领域模型包括很多类,比如说,AccountTransaction,然而food to go这个应用程序中的领域模型包括一些类比如OrderRestaurant。看看实例总是有用的,所以让我们把注意力集中到food to go的领域模型部分吧,如下所示

<v:shape id="_x0000_i1027" style="WIDTH: 6in; HEIGHT: 516pt" type="#_x0000_t75"><v:imagedata o:title="3" src="file:///C:\DOCUME~1\azhang\LOCALS~1\Temp\msohtml1\03\clip_image003.jpg"></v:imagedata></v:shape>

这张图上有很多细节的地方,但是让我们把注意力集中在最重要的类上,关键的类有如下这些:

<o:p> </o:p>

       PlaceOrderService:定义了Place Order这个用例的步骤并且更新领域模型对象。

<o:p> </o:p>

       PendingOrder:这个程序的购物车。PendingOrder有一个递送时间的属性和一个递送地址,一个物品列的集合,一个关联的restanurant,还有一个coupon。每一个物品有一个quantity属性和一个关联的MenuItem

<o:p> </o:p>

       Restaurant:代表了一个restaurant,它可以为你准备递送给你食物。一个restaurant有一个name属性和一个或多个menu item可以递送,一个物理服务区域(包括一个区号的集合)和一个开发时间。

<o:p> </o:p>

       MenuItem:描述了一个menu item,有一个name,一个描述,和一个价格。

<o:p> </o:p>

       TimeRange:由每个星期中的天组成,包括开始时间和结束时间

<o:p> </o:p>

       Order:代表一个在place order(提交订单)用例结束时被创建的order。像PendingOrder(还未提交的订单)有一个递送地址,物品列,和一个餐馆,它也可以拥有一张优惠券。理论上来说我们可以用Order类来代表一个order被输入而且确认。但是这将使程序变得更加复杂。使用两个分离的类可以简化设计。

<o:p> </o:p>

       Coupon:代表了一个可以给订单打折的折扣。Coupons使有代码确定的而且只在一个具体的时间内有效。Coupon类是Strategy(策略)模式的一个例子。像第一章你所看到的OverdraftPolicy一样,它使一个有多个实现的接口-每个实现都是一种coupon

<o:p> </o:p>

       PendingOrderRespository:定义获取(一般是从数据库)并且创建PendingOrder对象的方法。

<o:p> </o:p>

       OrderRepository:定义获取(一般是从数据库)并创建order对象的方法

<o:p> </o:p>

       RestaurantRepository:定义获取(一般是从数据库)restaurant的方法。

<o:p> </o:p>

       当然也有其他一些类,比如Address类,代表了一个addressPaymentInfomation类,保存这支付信息。

<o:p> </o:p>

       这些是相当简单的领域模型,但是它仍然有相当一部分类。企业应用的完整的一个领域模型将包含更多的类。如果你知道了不同的类所扮演的角色,那么用你自己的方法来发现领域模型将会简单的多。

<o:p> </o:p>

3.1.3 领域模型中的角色

       尽管来自不同问题域的领域模型有很大的不同,但是在领域模型中可以以角色来给这些类进行分类。确定一个类所扮演的角色将使对类的命名变的简单而且对设计领域模型来说也是有帮助的。正如你将要看到的,一个类的角色暗示了它在领域模型中的职责和与其他类的关系。理解这些角色将帮助你开发你自己的领域模型。

<o:p> </o:p>

       对于角色来说有几种不同的命名规定。我最喜欢的方案是基于Domain-Driven Design(领域驱动设计),有下面几种角色:

<o:p> </o:p>

       Entities:有独特身份的对象

      

       Value objects:没有独特身份的对象

<o:p> </o:p>

       Factories:定义创建entities的方法

<o:p> </o:p>

       Repositories:管理entities的集合并且封装持久化框架(相当于DAO吧)

<o:p> </o:p>

       Services:实现一些不能由单一类完成的职责而且封装领域模型(业务逻辑)

<o:p> </o:p>

让我们看看上面所示的这些角色

<o:p> </o:p>

entities

      

       entities是拥有独特业务特性的对象,这些业务特性和这些对象的属性的值是分开的。即使他们的属性值是一样的这两个entities也是不一样的,他们不能相互代替对方被使用。确认一个entities是很重要的,因为他们经常是对应于真实世界的概念并且是领域模型的核心。这个例子中的entitiesPendingOrderOrderRestaurant

<o:p> </o:p>

Value objects

<o:p> </o:p>

       Value objects是一些对象,这些对象主要是由他们属性的值来定义。他们经常是不可变的,这意味着一旦他们被创建了,他们就不能被更新了。两个属性的值是相同的实例可以互换使用。在上面这个领域模型的例子中,这种value object的例子包括PaymentInfomationAddress

<o:p> </o:p>

Factories

<o:p> </o:p>

       一个java应用程序用一种new操作符来创建对象。有时候,直接使用一个new操作符是足够了,但是如果你想具体示例一个复杂的对象图解或者你需要改变被创建对象的类型,那么你也许需要使用一个factory。一个factory定义了创建entities的方法。它封装了示例对象图解的机制而且将他们连接起来,简化了客户端的代码。<o:p></o:p>

Repositories

<o:p> </o:p>

       Repositories管理着entities的集合定义了获取和删除entities的方法。他们也可以扮演一个工厂的角色如果这个工厂的代码是够简单的话。一个repository封装了持久化框架并且是由一个接口和一个该接口的实现组成。接口定义了可以被repository客户端调用的方法,接口的实现通过调用持久化框架来实现接口的功能。因为持久化框架被封装在接口之后,所以你可以把注意力集中在业务逻辑的开发上,而不需要被数据库的问题拖后腿。

<o:p> </o:p>

Services

<o:p> </o:p>

       第五个也是最后一种在领域模型中发现的对象是services,它实现了应用程序的工作流。这些类是应用程序的驱动力,他们包含了实现一个用例的方法。一般说来,service包含了一个单一的entity不能包含的行为,也包含了操作多个其他对象的方法。在这个领域模型中的一个service的例子是PlaceOrderService,它包括定义了对应于Place Order用例步骤的方法。

<o:p> </o:p>

       一个service包括一个接口和一个实现类。它会被领域模型客户端所调用。这些客户端可以是facade或者是表现层。一个service方法很少会去实现一个意义重大的业务逻辑。相反,一个典型的service的方法会使用repository来得到对象并且委派他们为代表。比如说,PlaceOrderService调用RestaurantRepository并且PendingOrderRepository并且大多数委派给PendingOrder

<o:p> </o:p>

       一个领域模型中定义的方法非常类似于那些session facade中和pojo facade中定义的方法。方法经常是对应于用例的步骤。然而,一个service,不同于facade,它不会处理一些事情,如事务,取数据返回到表现层,游离对象,和所有那些facade所做的事情。取而代之的是,它只是把注意力集中在纯粹的业务逻辑上。把servicefacade中分离开来是很有用的,因为你可以在service上工作,而且领域模型的其他部分也不用担心“plumbing”和其他基础组织结构的问题。事实上,正如你在下面的部分将要看到的那样,当你实现一个领域模型的时候,service是一个开始的好地方。

<o:p> </o:p>

3.2 开发一个领域模型

<o:p> </o:p>

       现在你已经知道什么是一个领域模型而且如何把它融入到一个应用程序架构中,那么,让我们后退一步看看我们如何从打草稿开始来开发一个领域模型。开发领域模型的过程需要应用程序的需求,他们一般是用例或者用户故事,而且创建了一个可以执行的测试用例模型。开发领域模型有很多种方法,你可以使用适合你自己的开发策略。在这一部分中,我将描述一个简单,非正式的方法,这个方法以前很适合我。这也是一个你可以用来为自己的程序开发一个领域模型的方法。

<o:p> </o:p>

3.2.1 确定类,属性,和关系

       像其他的软件设计活动一样,设计一个领域模型需要可靠的对问题域的理解和某种程度上的创造力,经验,和普通场景。一个开始的好方法是和理解问题域的商业人士交流然后分析用例。在描述问题域的时候通常用一个名词来表示类名。Applying UML and Patterns提供了一个有深度的讨论是关于如何来确定一个类,属性,和联系的。

<o:p> </o:p>

       很正常的,在实例程序的例子中,food to go的商业人士和place order用例都可以使用像OrderRestaurantMenu ItemCouponAddress,和Payment Information这些词汇,这些都是似是而非的类。此外,从我们过去的经验可以得知这个程序需要一个购物车的概念,它代表我们需要一些类来存储订单的信息。分析域并且应用一个小数量的创造性的受益,领域模型如图3.3所示。

<o:p> </o:p>

       这个领域模型是你早先在图3.2中看到的一个更为简单的版本。在这个版本中的领域模型,类只有属性和关系;方法还没有被确定。此外,这个领域模型只定义了如PendingOrderRestaurantentity,也定义了如AddressTimeRange这样的value object。它没有定义PendingOrderRepositoryRestaurantRepositoryOrderRepository或者PlaceOrderService。尽管假设这些类的存在是有理由的,然而在下一部分中,我们将用决定领域模型类的行为来代替确定他们的身份。

<o:p> </o:p>

3.2.2给领域模型添加行为

<o:p> </o:p>

       到目前为止,领域模型中的类只有属性和关联关系。当然这只是必须做的第一步,我们还需要通过给领域模型添加行为来使之具有生命力。为了确定他们的行为,我们必须确定他们的职责和协作关系。类的职责就是该类是所做的事(方法),所知道东西(属性),和决定什么,职责是由该类的一个或多个方法决定的。图3.1中的领域模型描述了每个类所知道的(东西),因为它定义了属性和关联。它没有说明的是类的职责,因为职责涉及到该类的所做的事或决定要做的事(就是类的行为)。一个类的协作者就是该类为了完成自身的职责而所调用的其他类。图3.1中的领域模型描述出了一些可能的协作者的轮廓,因为这些协作者描述了类之间的关联关系。然而,正如我们将看到的,有更多的事情等待着我们去发现。

<o:p> </o:p>

<v:shape id="_x0000_i1026" style="WIDTH: 450pt; HEIGHT: 396pt" type="#_x0000_t75"><v:imagedata o:title="3" src="file:///C:\DOCUME~1\azhang\LOCALS~1\Temp\msohtml1\03\clip_image005.jpg"></v:imagedata></v:shape>

<o:p> </o:p>

那么,我们怎样去决定类的职责和协作者呢。已经有很多的书了,有描述了各种各样的超出形式范围oo设计技术的书,有相对少部分的书描述了基于uml的职责驱动设计技术,和基于代码的测试驱动开发技术。在这一章中,我将告诉大家我最喜欢的一种方法,它包括了以下一些步骤:

<o:p> </o:p>

       1  通过分析需求(用例,或用户故事)或界面设计来确定应用程序必须处理的请求。

      2  决定领域模型必须暴露的接口(类型和方法),这样做是为了确保表现层和业务逻辑层的facades能够处理这些请求。

       3  用测试驱动的方法来实现接口,使用测试驱动方法的时候要考虑返回的每一个请求。

<o:p> </o:p>

让我们先看看每一个步骤然后再看看如何应用他们。

<o:p> </o:p>

确定请求:

       给领域模型添加行为的第一步就是确定应用程序需要处理的请求和应用程序如何来响应这些请求。当应用程序从客户端接受到一个请求的时候,它必须处理请求然后返回合适的应答。比如说,在一个web应用程序中,当一个用户执行了一个填写表单或者点击链接的动作,他们的浏览器就会发送一个http请求(request)然后应用程序返回一个html页面。表现层通过直接或者间接的调用领域模型来处理请求,领域模型执行计算,更新数据库,得到需要的数据。因此,我们可以通过分析请求来决定领域模型必须暴露(给其他层)的接口――类型和方法。

<o:p> </o:p>

       我们可以通过分析程序的用例或者用户故事或者ui界面的设计来确定应用程序必须执行的请求。ui界面的设计指定了用户的动作,比如,提交表单,鼠标点击,明确地指定应用程序必须执行的请求。用例经常定义一个请求的队列。比如说,考虑一下你在第二章看到的place order用例:

<o:p> </o:p>

用例:

用户输入送货地址和时间。系统首先核实送货时间还未到,然后核实至少有一家餐馆提供送货信息。然后,系统更新这个未提交的订单的送货信息,并且显示可以提供服务的餐馆的列表。

<o:p> </o:p>

用户选择一个餐馆。系统把这个未提交的订单上的送货餐馆更新为该餐馆,并且显示被选择餐馆的提供的菜单。

<o:p> </o:p>

用户决定菜单上每个物品的数量。系统更新了未提交订单上的物品的数量。然后显示更新过后的未提交的订单信息。

<o:p> </o:p>

用户输入支付信息(信用卡信息和帐单信息)。系统更新整个未提交订单上的支付信息然后显示订单上的费用总和,应交税款和找零。

<o:p> </o:p>

用户确定她要发出订单(place order)。系统批准了信用卡的使用,创建订单然后显示一个订单确认的信息,该信息包含订单号。

<o:p> </o:p>

<o:p> </o:p>

用例的每一段都包含了两部分。第一部分描述了用户执行的一个动作,例如输入一个值或者作出一个选择然后作为一个http请求发送给web应用程序。place order(订单提交)用例暗示着应用程序必须执行以下请求:

<o:p> </o:p>

1 输入发货信息――用户输入发货信息

2 选择餐馆――用户选择一个餐馆

3 更新数量――用户输入菜单中(想购买的)物品的数量

4 支付――用户声明她已经输入了物品数量的信息

5 输入支付信息――用户输入支付

分享到:
评论
1 楼 ahuaxuan 2007-01-09  
书中的代码我都是截图的,本来有好多图的,但是这个webeditor好像不支持直接复制图片,fckeditor是支持的

相关推荐

    Manning - Pojos In Action

    《Pojos in Action》是一本专注于Java编程领域中Plain Old Java Objects(POJOs)技术的专业书籍。这本书由Manning出版社出版,旨在深入探讨如何在实际开发中有效地使用POJOs,以及它们在现代Java应用程序设计中的...

    Manning - Pojos In Action.pdf

    《Pojos In Action》这本书由Chris Richardson撰写,聚焦于使用POJOs(Plain Old Java Objects)设计轻量级Java企业应用的关键问题,通过深入的实例解析,为读者提供了实践指导。该书不仅扩展了Martin Fowler的...

    POJOS in Action

    《POJOS in Action》是一本专注于简单Java对象(Plain Old Java Objects,简称POJOs)的实战指南,由Manning出版社在2005年出版。POJOs是Java编程中的一个基本概念,它代表那些没有特殊框架依赖、遵循传统Java类结构...

    pojos_in_action_-_src.zip

    "pojos_in_action_-_src.zip" 这个压缩包文件,暗示我们它包含了与《Pojos in Action》一书相关的源代码。这本书主要讲解了Plain Old Java Objects(POJOs)的使用和实践,POJOs是Java开发中的基本元素,代表了没有...

    POJOS IN ACTION开发轻量级企业应用程序

    POJOS IN ACTION开发轻量级企业应用程序

    pojos in action

    《Pojos in Action》是一本深入探讨Java轻量级解决方案的经典教程,它主要针对企业级应用开发领域,尤其关注EJB(Enterprise JavaBeans)编程模型的局限性以及为何转向POJOs(Plain Old Java Objects)和轻量级框架...

    POJOs.in.Action

    《POJOs in Action》为Java开发者提供了一个全面而深入的学习资源,不仅介绍了轻量级框架的基本概念和技术细节,还通过丰富的实践案例展示了如何在真实项目中有效地应用这些技术。对于希望深入了解POJOs及其相关框架...

    Pojos In Action

    综上所述,《Pojos In Action》这本书不仅是一本关于POJO技术的指南,更是对现代Java企业应用开发的一次全面探索。它不仅覆盖了理论知识,还提供了丰富的实践经验和案例分析,对于希望深入了解轻量级Java企业应用...

    《POJOs in Action》(pdf)英文版下载

    本书摘自Chris Richardson撰写的POJOs in Action (ISBN 1932394583),由Manning Publications公司出版,版权所有:2006年。 博文链接:https://projector.iteye.com/blog/209555

    POJOs入门到精通

    **POJOs(Plain Old Java Objects)*...通过“POJOs入门到精通”这本指南,无论是初学者还是有经验的开发者,都能系统性地学习和掌握POJOs的核心概念和最佳实践,从而在实际项目中更好地运用这一基础但至关重要的技术。

    Generate POJOs.groovy

    IDEA通过Generate.POJOs.groovy映射数据库自动生成对应的Java实体类, 具体逻辑不详细展示,可参考:https://blog.csdn.net/weixin_40375601/article/details/106807644

    MyVo Generate POJOs.groovy.zip

    在给定的压缩包文件"MyVo Generate POJOs.groovy.zip"中,包含了一系列以"Generate POJOs.groovy"命名的脚本,如"My Generate POJOs.groovy"、"MyDto Generate POJOs.groovy"、"MyInsertDto Generate POJOs.groovy...

    spring in action Thrid 第一章重点内容

    在Spring in Action第三版的第一章中,主要探讨了Spring框架如何简化Java开发,并阐述了Spring的核心理念和策略。Spring框架的出现是为了应对Java开发中的复杂性问题,它通过四个关键策略来实现这一目标: 1. **轻...

Global site tag (gtag.js) - Google Analytics