Data Transfer Object
在一个ejb系统中的客户端层需要一种向服务器往返
传输大块(bulk)数据的方法。
客户端怎样能和服务器交换大块数据而无需多个细粒
度网络调用呢?
在一个分布式应用中,客户端和服务器交互通常可能
有两个原因。第一个是从服务器上读取一些数据来显
示;第二个是通过创建,更新,删除数据来改变服务
器上的数据。在一个ejb环境,这些类型的操作通常
涉及和客户端(servlet,applet,等等)和一个session
bean,entity bean,或message-driven bean交换数据。
当巨大数量的数据需要被交换,这可以通过两种方法
达到:1。装载许多参数到一个方法调用(当更新服务
器上的数据),或用2。许多细粒度调用从服务器取到
数据(当客户端需要从服务器读取数据)。当处理大量
参数时前一种方法将迅速失去控制,而后一种方法将
是性能杀手。
想象一下当客户端UI需要显示服务器上的一个属性的
集合的情境;这些属性存在于一个entity bean中或
可通过一个session bean存取。客户端能得到它所需
要的数据的一个方法是执行多个对服务器的细粒度的
调用,如图2.1所示。
这种方法的问题是每个对服务器的调用是一个网络调用,
需要对返回值序列化和反序列化,当ejb服务器截获对
服务器的调用并完成事务和安全性检查时阻塞了客户端,
并且这时当然对属性的接受未知。更进一步,如果客户端
没有使用Java Transaction API client-demarcated事务,
每个方法调用可能实际上在它自己的分离的事务中执行。
用这种形式执行多个网络调用将导致严重的性能下降。需要
一个更好的替代方法,该方法允许客户端在一个大块(bulk)
调用中得到所有需要的数据。
综上所述:
创建叫做data transfer object的普通Java类,
在一个network transportable(跳跃) bundle
(扎,束)中包含和封装大块(bulk)数据。
一个data transfer object是一个普通可序列化
的java类,它代表一些服务器端数据的快照(snapshot),
如下面例子:
import java.io.Serializable;
public class SomeDTO implements Serializable{
private long attribute1;
private String attribute2;
private String attribute3;
...
public long getAttribute1();
public String getAttribute2();
public String getAttribute3();
...
}//SomeSTO
在一个分布式系统中可以把Data transfer object用作
读取操作和更新操作。当一个客户端需要更新服务器上
的一些数据时,它能创建一个封装所有服务器需要去更新
的信息的DTO,并传到服务器(通常是一个session facade)
去处理。当然,它也能用成万亿的细粒度参数来传输数据
到服务器,不过这是一个非常脆弱的方法。每当一个参数
需要去被增加或删除,方法签名需要改变。通过用DTO封装
方法参数,变化只被孤立到DTO自己身上。
明显需要data transfer object的地方是读操作。当一个
客户端需要读一些服务器端数据(为了传递到客户端UI目的),
客户端能通过在data transfer object的形式封装数据来
在一个大块(bulk)网络调用中得到所有数据。
使用先前的例子,服务器端ejb将创建一个DTO(如图2.2所示),
并用客户端需要的属性传输它。这数据将用一个大块返回值
(data transfer object)返回到客户端。data transfer
object基本上是一个“信封”,用来在J2EE系统的各层间
传输任何类型的数据。
当使用data transfer object时,开发者面对的一个
常见的问题是:用什么粒度设计它们。也就是说,你怎
样选择用DTO封装多少数据?你怎样决定是否需要DTO?
作为首要的在客户端和服务器间交换的方法,data
transfer object建立了分离客户端开发者和服务器
开发者的接口。在一个项目的开始阶段,客户端和服务器
开发者需要在决定使用什么ejb interface的同时决定
data transfer object的设计。不管这个需要,因为
开发者通常不完全懂得什么数据单元应该在客户端和服务器
之间传输,所以在项目开始阶段设计data transfer object
是很困难的。
开始设计data transfer object的简单方法是作为服务器端
entity bean的拷贝(或领域对象),如Domain Data Transfer
Object模式所述。设计Domain Data Transfer Object很简单,
因为项目小组通常有项目可以初期使用的好的领域模型。因此,
把Domain DTO作为客户端和服务器之间的交换能让小组启动和
运行得更快。
终极的,客户端和服务器之间交换的数据应该设计得去满足
客户端的需要。因此,当项目进行并且客户端的需要满足了,
Domain Data Transfer Object作为交换单元经常变得难用,
太过于粗粒度以至于无法满足客户端的细粒度需要。一个客户
端可能需要存取没有被封装在任何Domain Data Transfer
Object中的数据。在这一点上,开发者可以设计custome Data
Transfer Object,就是说,封装任意数据集的Data Transfer
Object,完全被客户端的特定需求所驱动。
这两种设计paradigm的区别会对整个应用的设计产生显著
影响。虽然它们代表自相矛盾的方法,他们可以通常在
任何J2EE应用中共生。
当决定何处放置创建和消耗Data Transfer Object的逻辑
时,Data Transfer Object Factory模式描绘了一个可行的
并且可维护的解决方案。一个和跨层(DTO,HashMap,RowSet)
的任何种类的数据传输一起发生的事件是:当数据到达客户端
时,它有潜在的不是最新的可能性。Version Number模式
能解决这个问题。
相关模式
State Holder
value Object
Details Object