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

04-06-25 holykeeper
我是Java初学者,最近在学习EJB时遇到一个问题:

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

无道
2004-06-25 16:16
这恐怕就是分层结构的硬伤了,分层结构在解耦的同时也把一些有用的耦合分解开了,因此就需要各种各样的胶合剂来弥补层与层之间的缝隙.DTO就是其中的一种.

可使用代码工具来减少一些工作量.

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

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

banq
2004-06-26 20:19
这个问题非常有意思,其实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变化导致修改环节太多,太琐碎,而我在实践早发现这个问题,使用自己的框架来建立这种纵向联系。

holykeeper
2004-06-27 17:20
谢谢各位前辈给我的指点,明白一些了.

我参考了banq的“数据操作通用框架的使用”的示范代码,还有一点不太明白,想请教banq:

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

banq
2004-06-27 18:47
我的框架只是给出一个答案,不知其它人是否有其它解决方案?

to holykeeper

关于你的回复,转到这里讨论:

http://www.jdon.com/jive/thread.jsp?forum=61&thread=14883

halcyon
2004-08-10 14:03
其实我觉得这里存在着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());

}

}

halcyon
2004-08-10 14:04
刚才打错了几个字:

当entity对象的属性发生变化的检查条件该为:public类型的成员的值被改变或setXX被调用

halcyon
2004-08-10 14:13
如果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了吧.当然,其中的安全问题还有待讨论

banq
2004-08-10 15:45
halcyon 见解非常独特,在消化中...,.好。

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

anonymous
2004-11-17 13:42
我没有用dto这种结构。感觉太繁琐。

猜你喜欢