- 浏览: 639597 次
- 性别:
- 来自: 杭州
文章分类
最新评论
-
liuche20083736:
非常好
从问题看本质: 研究TCP close_wait的内幕 -
xiaopohai85707:
优化算法与原来需求不符
过滤字符的性能调优?挤一挤还是有的 -
kmy_白衣:
生成的area图有时候 标签的数值和图标上看上去的数值不一致。 ...
OpenFlashChart2之恶心文档 -
tom&jerry:
大神,请教一个问题,按名称排序为何无效,用的2.4.3 XPA ...
深入浅出jackrabbit之十三 查询之AST和QT -
jd2bs:
改成精确匹配可以了< filter-mapping &g ...
细谈Ehcache页面缓存的使用
用jMock来实现这一点,然而,我们至少需要定义PendingOrderRepository接口并且写一个PendingOrder的stub(桩)实现。PendingOrderRepository接口定义了一个findOrCreatePendingOrder()方法:
<o:p> </o:p>
public interface PendingOrderRepository{
<o:p> </o:p>
PendingOrder findOrCreatePendingOrder(String pendingOrderId);
}
<o:p> </o:p>
PendingOrder类为updateDeliveryInfo()方法定义了一个桩,该桩将在后面一点实现:
<o:p> </o:p>
public class PendingOrder{
<o:p> </o:p>
public boolean updateDeliveryInfo(Address deliveryAddress,
Date deliveryTime){
return false;
}
}
<o:p> </o:p>
updateDeliveryInfo()方法的桩返回假。
<o:p> </o:p>
完成测试
<o:p> </o:p>
我们已经编写了updateDeliveryInfo()方法并且定义了PendingOrderRepository接口和PendingOrder类,但是这时我们需要修正一下我们之前编写的测试程序。它不需要再编译一次因为PlaceOrderServiceImpl的构造方法通过被传递了一个PendingOrderRepository参数而具有了我们预期的行为。另外,测试程序必须创建和配置模拟的(假的)PendingOrder和PendingOrderRepository。这个模拟的(mock)PendingOrderRepository被期望来调用它的findOrCreatePendingOrder()方法并且返回一个模拟的(mock)PendingOrder。PendingOrder被期望来调用它自己的updateDeliveryInfo()方法。表3.4显示了一个更新测试。
<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_i1027" style="WIDTH: 6in; HEIGHT: 396pt" 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>
<v:shape id="_x0000_i1028" style="WIDTH: 6in; HEIGHT: 243pt" 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>
<v:shape id="_x0000_i1026" style="WIDTH: 6in; HEIGHT: 225pt" 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>
让我们来看看这段测试程序做了哪些事
<o:p> </o:p>
1 测试用例继承了jMock的MockObjectTestCase类,它能自动的检验mock对象的预期行为是否能被满足。
<o:p> </o:p>
2 setUp()方法创建了模拟的(mock)PendingOrderRepository、PendingOrder和PlaceOrderService。
<o:p> </o:p>
3 测试程序定义了mock对象的预期行为和返回结构。模拟的PendingOrderRepository被计划用发货信息来调用findOrCreatePendingOrder()并且返回模拟的(mock)PendingOrder。模拟的(mock)PendingOrder被计划通过以发货信息为参数来调用其updateDeliveryInfo()方法。它返回true则表示发货信息是有效的而且PendingOrder被更新了
<o:p> </o:p>
4 在配置了预期行为之后,测试程序调用了PlaceOrderServe的updateDeliveryInfo()方法。
<o:p> </o:p>
5 然后测试程序断言调用是否成功,并且检验PlaceOrderService返回的模拟的(mock)PendingOrder。它不再检验PendingOrder是否包含了正确的发货信息因为它假设PendingOrder.updateDeliveryInfo()的行为是正确的。
<o:p> </o:p>
正如你能看到的,这个方法和它的测试程序有着很简单的关联关系,因为大多数的业务方法只是很简单的调用其他领域模型的对象(或者是领域模型中的其他对象)。因为利用了这些mock对象,我们就可以在不投入到它们(PlaceOrderService用到的类)的实现细节中也能开发和测试PlaceOrderService。
<o:p> </o:p>
<o:p> </o:p>
3.3.2 实现一个领域实体的方法
<o:p> </o:p>
我们已经实现了我们的第一个方法,它通过了测试并且能够正常工作!但是我们仍然还有很多事要做。当实现PlaceOrderService.updateDeliveryInfo()时,我们决定把它的职责分配给PendingOrder,PendingOrder是一个领域模型中的实体(entity),然后调要它的updateDeliveryInfo()方法。这个方法检验发货信息并且更新PendingOrder。它返回一个能表明发货信息是否有效的布尔值。让我们来看看如何来实现这个方法。
<o:p> </o:p>
写一个测试
<o:p> </o:p>
像之前那样,我们先写一个测试程序。表3.5是一个简单的测试,通过传递给该方法一个有效的发货信息来测试该方法是否能通过。它使用了不可见的RestaurantTestData来创建一些测试数据。
<v:shape id="_x0000_i1025" style="WIDTH: 486pt; HEIGHT: 435pt" type="#_x0000_t75"><v:imagedata o:title="3" src="file:///C:\DOCUME~1\azhang\LOCALS~1\Temp\msohtml1\03\clip_image006.jpg"></v:imagedata></v:shape>
<o:p> </o:p>
该测试用例用一个有效的发货信息调用了PendingOrder.updateDeliveryInfo()方法并且检验它是否更新了PendingOrder,返回值是否为真。
<o:p> </o:p>
实现方法
<o:p> </o:p>
因为PendingOrder已经定义了一个桩方法,那这个测试编译的时候就不会有问题。但是为了使之运行通过,我们需要用一个真实的实现来代替这个桩,从而可以使之可以检验发货信息和更新PendingOrder。
<o:p> </o:p>
PendingOrder首先用Calendar类来检查发货信息中的发货时间是否在一小时以后。然后查询数据库来检验发货信息。最简单的方法是在RestaurantRepository里封装这个查询并且定义isRestaurantAvailable()方法。updateDeliveryInfo()方法调用isRestaurantAvailable,如果其返回值为真就把发货信息存储到数据库。
<o:p> </o:p>
<v:shape id="_x0000_i1029" style="WIDTH: 6in; HEIGHT: 410.25pt" type="#_x0000_t75"><v:imagedata o:title="3" src="file:///C:\DOCUME~1\azhang\LOCALS~1\Temp\msohtml1\03\clip_image007.jpg"></v:imagedata></v:shape>
一个我们没有解决的很重要的设计上的问题是,PendingOrder如何访问RestaurantRepository。让我们来看看如何解决这个问题。
<o:p> </o:p>
选择如何访问一个repository
<o:p> </o:p>
Repositories主要是被领域中的service类来使用,但是他们也被一些实体调用,比如说entities。为调用一个repository对象的方法,调用者必须显示的拥有整个对象的引用。之前你看到如何把repository作为一个参数传递给PlaceOrderService的。然而,在领域模型的entity中有时候这却是行不通的,且听我娓娓道来。让我们把问题揭示出来然后再给大家讲讲几种解决方案。
<o:p> </o:p>
最方便的方法是把repository作为参数传递给entities,就像传递给service一样。这样可以使用轻量级容器的构造方法注入机制来初始化实体。把repository作为参数传递给构造方法比传递给一般的方法要简单得多而且也没有使用单例模式时的缺点了,我将在后面一点讲解单例模式。然而使用这种方法来初始化entity不是易懂的,因为它不同于service,service由轻量级容器来负责初始化,而entity则由持久化框架在从数据库里读取数据的后创建。
<o:p> </o:p>
默认情况下,持久化框架是直接使用类的默认构造方法来创建对象的,所以不可能把任何需要的对象传递进它(将被创建的entity)构造方法。一些(不是所有的)持久框架有配置对象初始化的机制,这样可以允许程序来控制如何初始化entity。程序可以用具有依赖注入的轻量级框架来配置持久化框架以便于创建对象。比如说使用hibernate 的构造器注入。然而,因为该方法并不是一种普遍的方法,所以在本书中我不会使用它。
<o:p> </o:p>
另一个选择是用静态方法和变量来实现repository。举个例子,你可以用ThreadLocal模式或者单例模式来实现一个repository。这种方法可以使用在任何的持久化框架中,而且不需要把repository传来传去,但是有时会把代码弄得太复杂。使用静态方法和变量的问题是它们会把代码弄得难以测试。比如说,它们阻止你使用一个可变的实现如一个mock对象,因为你不能改变程序对一个静态方法的调用,也不能改变它来访问另一个类的静态变量。它们也引入了隐藏的依赖关系,因为代码取决于那些必须被初始化的静态变量。因此,最好避免使用静态方法和静态变量。
<o:p> </o:p>
知道了只有一些持久化框架允许你使用构造方法注入来初始化entity并且使用静态方法和变量有很多严重的缺点,那么把repository作为参数传递给方法就有意义了。它避免了使用单例模式的缺点也不设计到所有的持久化框架的特点。然而,采用这种方法的一个缺点是,它在代码中有一个一石激起千层浪的效果(ripple effect)。我们也许不得不改变很多方法来把repository作为一个参数传递给该方法使用,这个repository由service传递过来,service是通过构造器注入来拥有了repository的引用的。
<o:p> </o:p>
在这个例子中,把RestaurantRepository传递给PendingOrder只需要作很小的改动。我们只需要改动PlaceOrderService来把RestaurantRepository作为一个参数传递给PendingOrder的updateDeliveryInfo()方法,而RestaurantRepository应该是PlaceOrderServie的构造方法的一个参数。
表3.6显示了PendingOrder.updateDeliveryInfo()方法。
<v:shape id="_x0000_i1030" style="WIDTH: 450pt; HEIGHT: 372pt" type="#_x0000_t75"><v:imagedata o:title="3" src="file:///C:\DOCUME~1\azhang\LOCALS~1\Temp\msohtml1\03\clip_image009.jpg"></v:imagedata></v:shape>
<o:p> </o:p>
这个方法调用了RestaurantRepository.isRestaurantAvailable()方法,如果返回true,那么就把发货信息更新到PendingOrder。
<o:p> </o:p>
为了使这个类通过编译,我们需要定义isRestaurantAvailable()方法;
<o:p> </o:p>
public interface RestaurantRepository{
boolean isRestaurantAvailable (Address deliveryAddress,
Date deliveryTime)
}
<o:p> </o:p>
如果至少有一家餐馆提供了发货信息中指定的服务则返回true。我们也不得不改变PlaceOrderService来把RestaurantRepository传递给其构造方法,并且也要把RestaurantRepository传递给PendingOrder ,同时要用模拟的(mock)RestaurantRepository来改变PendingOrder的测试类。
发表评论
-
过滤字符的性能调优?挤一挤还是有的
2010-05-29 05:54 3610/* *auth ... -
Master-Slave,Spring,Hibernate,故事曲折离奇,情结跌宕起伏
2009-02-05 13:49 8684/** *作者:张荣华 *日期 ... -
弃成见,反省,并重新认识struts.i18n.encoding
2008-12-24 15:42 3880[size=medium]之前和大家讨论了struts2.0中 ... -
关键字:查询,事务,粒度
2008-08-22 17:05 5138[size=medium]/** *作者: ... -
看看mina和memcached的联姻(适合不同语言客户端,高并发?)
2008-07-21 17:06 7984[size=medium]/** * 作者:张荣华 * 日 ... -
如何解决mysql的master-slave模式中ReplicationDriver的使用问题
2008-06-19 18:23 8220/** * 作者:张荣华 * 日期:2008-6-19 ... -
别装了,难道你们不想把properties直接注入到object中去(spring-plugin)?
2008-04-09 18:01 3651[size=small]/** *作者:张荣华(ahuaxu ... -
用jamon来监控你的sql执行效率
2008-02-25 15:48 3716/** *作者:张荣华 *日期:2008-2-25 ... -
java同msn的通信,大家想想用途吧
2007-11-24 17:14 2513程序员的生活真是单调,除了编程还是编程,工作日 ... -
EAI企业应用集成场景及解决方案
2007-09-21 18:21 3154/** *作者:张荣华(ahuaxuan) *2007-9 ... -
quartz和应用的集群问题
2007-08-21 18:36 12817之前看到很多关于quartz的讨论,尤其是关于quar ... -
优化程序之前,可用Jamon来监测你的Spring应用
2007-08-14 18:14 8125/** *作者:张荣华(ahuaxuan) *2007-8-1 ... -
请问责任链真的是一种设计模式吗
2007-07-26 18:12 9414坛子上讨论设计模式的也挺多的,但是关于这个责任链模式还没有人提 ... -
把ActiveMQ的控制台整合到你的web程序中
2007-07-19 12:06 8830在使用ActiveMQ的时候把ActiveMQ的控制台整 ... -
设计模式之:解剖观察者模式
2007-07-17 16:12 6866[size=9] 论坛上很多人都 ... -
java邮件:在简单和复杂之间的方案
2007-07-11 18:07 7584/** *作者:张荣华(ahuaxu ... -
强强连手, 在模板中分页,看Freemarker和displaytag的结合
2007-07-09 09:22 6926/** *作者:张荣华(ahuaxuan) *2007-0 ... -
解惑:在spring+hibernate中,只读事务是如何被优化的。
2007-06-28 18:22 7622/** *作者:张荣华(ahuaxuan) *2007- ... -
让webwork零配置 第二章(实现)(实例已放出,大家可以下载运行)
2007-06-25 09:23 5708/** *作者:张荣华(ahuaxuan) *2007-0 ... -
让webwork2零配置,第一章(主贴再次更新)
2007-06-18 15:41 13379/** *作者:张荣华(ahuaxuan) *2007-0 ...
相关推荐
综上所述,《Spring in Action 第三版》第二章的核心内容是展示了Spring如何通过轻量级设计、依赖注入、声明式编程和减少冗余代码的策略,来实现Java开发的简化和优化。这些概念和实践贯穿整个Spring框架,为开发者...
总的来说,Spring in Action第三版第一章的重点在于介绍Spring如何通过上述策略简化Java开发,提升代码质量,使开发者能更专注于业务逻辑,而不是底层的基础设施。依赖注入是实现这些目标的核心工具,它使得松耦合...
### Spring in Action 第二版 — 关键知识点概览 #### 一、Spring框架简介与核心概念 - **Spring 框架概述**:Spring 是一个开源的轻量级 Java 应用程序框架,旨在简化企业级应用开发。它提供了一个全面的编程模型...
**第3章:Action与结果** 在这一章中,你会了解到Action类是业务逻辑的载体,它是控制器层的主要组成部分。同时,还会讲解Result类型,如dispatcher、stream等,以及如何根据不同的逻辑跳转到不同的页面。 **第4章...
第三部分可能深入讲解Struts2的拦截器。拦截器是Struts2框架的一大特色,它们可以按照预定义的顺序在Action执行前和执行后执行,实现诸如日志记录、事务管理、权限控制等功能。通过自定义拦截器,你可以进一步扩展...
10. **Ajax支持**:虽然Struts1本身并不直接支持Ajax,但可以通过Struts-Plugins或其他第三方库(如DWR或Prototype/Scriptaculous)集成Ajax功能,实现页面的异步更新。 总之,Struts API官方文档对于理解和使用...
学习这部分内容,你需要理解MVC架构、掌握Spring的核心特性,如IoC和AOP,熟悉Struts的配置和Action机制,以及MyBatis的SQL映射和结果映射。同时,对JavaEE的Servlet和JSP有基本认识,能熟练使用Eclipse这样的IDE...
Mybatis3是轻量级的持久层框架,Spring4则是一个全面的企业级应用框架,而Struts2则作为MVC架构的一部分,负责处理前端请求和后端业务逻辑的交互。 【描述】提到这个源码是共享学习的资源,意味着它包含了完整的...
短信服务通常通过第三方API实现,Spring的RestTemplate或者Feign客户端可以用来调用这些API,而Spring的配置和事务管理同样适用于短信服务的错误处理和事务一致性。 **TelePurdoWebQuery** 这个文件名可能是项目中...
mybatis实战教程mybatis in action之三实现数据的增删改查 mybatis实战教程mybatis in action之四实现关联数据的查询 mybatis实战教程mybatis in action之五与spring3集成附源码 mybatis实战教程mybatis in action之...
同时,Spring3集成了大量的第三方库,如MyBatis,使得整合各种技术变得更加容易。 **MyBatis** 是一个优秀的持久层框架,它支持定制化SQL、存储过程以及高级映射。MyBatis避免了几乎所有的JDBC代码和手动设置参数...
- **模块化**:Spring包含多个子框架,如数据访问/集成、Web、AOP(面向切面编程)、上下文和测试等,这些子框架可以独立使用,也可以与其他第三方框架集成。 - **非侵入式设计**:Spring的应用程序可以尽量减少对...
- 无缝集成各种第三方库。 - **使用场景**:几乎适用于所有的Java应用开发场景。 #### 3. Hibernate框架解析 Hibernate是一个开放源码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,使得Java开发者...
- **低耦合**:各组成部分之间相互独立,可以在不影响其他部分的情况下修改其中一部分。 - **高重用性**:模型可以被多个视图使用,提高了代码的复用性和维护性。 - **可扩展性**:易于添加新的视图或修改现有视图。...
在Web开发中,MVC模式是一种常用的设计模式,它将应用程序分为三个主要部分:模型(Model)、视图(View)和控制器(Controller)。WebWork框架通过这种方式,使得开发者可以更好地组织和管理代码,提高开发效率和可...
在本课程"【Java web实战员工管理系统】第十三讲"中,我们将深入探讨如何使用Java Web技术构建一个功能完备的员工管理系统。这个系统的核心目标是实现对企业内部员工信息的高效管理和便捷操作。Java Web作为企业级...
可以从官方网站或第三方网站下载。 2. 解压并部署 BlazeDS。将 `blazeds.war` 文件解压到 Tomcat 的 `webapps` 目录下。 3. 在 MyEclipse 中配置 Tomcat 服务器,指定 Tomcat 的安装路径,并启用服务器。 4. 创建...
1. **Action类**:这是控制器的部分,负责处理来自用户的请求,并调用模型进行业务处理。 2. **配置文件**:主要包括struts.xml,用于定义Action类、Action映射以及结果页面等。 3. **视图**:通常由JSP页面构成,...