如何降低DTO对象与系统其他部分的耦合?

我是Java初学者,最近在学习EJB时遇到一个问题:
在实体Bean与客户端进行数据传输时,往往会用到一些DTO对象。但如果实体Bean中的属性发生变化,比如新增加几个字段,这时DTO对象的属性也需要作相应的变化,而DTO对象在客户端和EJB中都有使用,所以很多代码都得改写,有没有什么模式可以减少DTO对象对其他部分的影响?

这恐怕就是分层结构的硬伤了,分层结构在解耦的同时也把一些有用的耦合分解开了,因此就需要各种各样的胶合剂来弥补层与层之间的缝隙.DTO就是其中的一种.
可使用代码工具来减少一些工作量.

系统分层次是为了减小减小各层次之间的耦合,但我认为想要达到0耦合是不可能的。正如Business Delegate减小了web层于ejb层之间的紧密耦合,但付出的代价是Business Delegate于ejb层之间的紧密耦合。正如楼上所说,这就像是两个层次之间的粘合剂。

DTO的目的不是为了减小耦合,而是为了减小远程调用的次数,因此DTO一定要紧密耦合于远程调用的双方,但换来了远程调用双方的松散耦合。

这个问题非常有意思,其实DTO是随着实体Bean变化的,现在jbuilderX已经提供从实体Bean直接生成的DTO的工具,说明DTO确实是依据实体Bean变化的。

所以,现在有些MDA工具,可以迅速根据Model变化,自动生成新的实体Bean和DTO等。

DTO变化肯定会影响Web层和EJB层的,所要做的只是缩小这种影响,一般我是将DTO影响限定在这个Model的增删改查框架内,因为我使用JdonSD的增删改查框架,因此,根据实体bean变化,可以迅速修改DTO变化,直至相应的客户端界面,这种修改不用担心会带来新的不稳定性和隐患。

而且,这种修改不会因为实体Bean的数据增加而显得麻烦,因为增删改查框架已经限定,每个实体Bean修改部位都是相同的,比如总是A B C三个地方。

不知道我说清楚没有?我的意思是,实体Bean变化是肯定的,现有的J2EE结构只是解耦了各层关系,但是没有提供一个沿着某个实体Bean这样纵向的联系,这样使得复杂实体Bean系统中,某个实体Bean变化导致修改环节太多,太琐碎,而我在实践早发现这个问题,使用自己的框架来建立这种纵向联系。


谢谢各位前辈给我的指点,明白一些了.
我参考了banq的“数据操作通用框架的使用”的示范代码,还有一点不太明白,想请教banq:

请问productForm是如何实现的?它和com.jdon.estore.model.Product之间的关系是什么,是否由JdonSD框架来处理二者的联系?

其实我觉得这里存在着java bean 设计上的很大一个缺陷
java bean设计了bound property,使其他对象可以监视一个bean的属性变化.但败笔就是在每个setXX()中都要显式地调用firePropertyChange()方法来通知,非常地不直观和方便.
其实这些东西都应该做成Interceptor方式的,这样才能做到代码透明,jboss和hibernate做的很好,可惜我没研究他们是怎么实现的.

所以,最完美的方式就是让java内置该功能,配合jdk1.5的tag功能:
class Entity{
@property_change_listener PropertyMonitor monitor;
...
public void setName(String name){...}
...
}
当entity对象的属性发生变化时(public类型的成员的值被改变),jvm会自动调用所有有@property_change_listener标签的成员变量的onPropertyChange方法(它们应该都是实现了java.beans.PropertyChangeListner接口,否则jvm报告ClassCastException)
这样就实现了完全松耦合,只是通过标签来联系.

example:
public class Entity {
@property_change_listener private PropertyChangeListener monitor;

private String name;
private int age;
private double price;

........
}

class Monitor implements PropertyChangeListener{
private Entity entity;
private DTO dto;

public Monitor(Entity entity,DTO dto){
this.entity=this.entity;
this.dto=dto;
}

public void propertyChange(PropertyChangeEvent evt) {
BeanUtils.setProperty(this.dto,evt.getPropertyName(),evt.getNewValue());
}
}

刚才打错了几个字:
当entity对象的属性发生变化的检查条件该为:public类型的成员的值被改变或setXX被调用

如果jvm真的实现了property改变时自动拦截,那更完美的方案会是(也是基于tag):

@property_synchronizer com.test.Entity com.test.DTO org.apache.strusts.ActionForm
Class Monitor implements java.beans.PropertyChangeListener{
public void onProerptyChange(){...}
}

@property_synchronizer可以同步任意多种对象,基本上entity和dto都不需要保存对方的引用,这样做就有点类似aop了吧.当然,其中的安全问题还有待讨论

halcyon 见解非常独特,在消化中...,.好。

我个人考虑能不能运用动态字节码的方法?在运行时或者是编译后自动为Bean中的每一个setXXX方法的最后添加一句通知listener。

我没有用dto这种结构。感觉太繁琐。