锁定老帖子 主题:开贴再论为何DTO在大型架构里是必须的。
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2004-12-02
背景:该产品拥有千万以上的系统用户资料,整个系统并发用户在100-1500之间。为某运营商一个核心系统。 架构:该产品采用了标准J2EE体系架构,MVC+SLSB+DTO+ORM作为我们的系统总体结构。 项目中我们采用Hibernate作为ORM,但是由于持久对象作为系统最基本的静态模型,其类度通常来讲都是比业务对象来得细小的。因此,系统中持久对象是不适合直接让业务逻辑层的人员看到的,据个例子来说:就我们最常见的客户资料,自然包括如客户的基本资料、个性化资料、亲情资料等等。这些资料自然对应一个个的持久对象。但是作为业务来讲,我创建一个客户,一般都是所有资料一起创建,业务看到的数据通常是各个持久对象的聚合。在这一层,勿庸置疑,大家应该都是采用值对象模式来实现的。 这样就产生一个问题,值对象的粒度和持久对象的粒度存在严格的阻抗不匹配。在实现上来讲,基于不同的业务逻辑,就需要把不同的持久对象构造为值对象。 从实际上来讲,似乎顺利成章应该业务逻辑来维护这个值对象和持久对象的阻抗不匹配的关系。但是经过我实际的项目实践,感觉这种做法其实并不是很好。 1、需要项目业务逻辑实现者了解Hibernate; 2、项目大部分业务逻辑代码都存在重复(或者逻辑重复); 鉴于此,有必要把值对象和持久对象的组合经过封装,过滤。说白了就是完成值对象和持久对象之间的自动映射。这个实现过程是非常简单的。完全可以采用Hibernate等ORM的持久对象和表之间的映射关系来实现。 目前我把这一层作为DTO来实现,现在业务逻辑开发人员就非常轻松了,也不用学习Hibernate了,他们看到的就是业务逻辑粒度的值对象的CRUD接口。业务逻辑的编写也变得非常轻松。系统的架构也因为层次的解耦而变得易于维护。 相关资料请参考我的Blog: http://yiqingju.blogdriver.com/yiqingju/index.html 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2004-12-02
引用 1、需要项目业务逻辑实现者了解Hibernate;
我组装一下持久对象也需要了解Hibernate???举个例子出来 引用 2、项目大部分业务逻辑代码都存在重复(或者逻辑重复);
如果1不成立,那么组装代码基本上没有,何来重复的说法? |
|
返回顶楼 | |
发表时间:2004-12-02
引用 引用: 1、需要项目业务逻辑实现者了解Hibernate; 我组装一下持久对象也需要了解Hibernate???举个例子出来 引用: 2、项目大部分业务逻辑代码都存在重复(或者逻辑重复); 如果1不成立,那么组装代码基本上没有,何来重复的说法? 同样以上面的客户资料为例,如果Hibernate之上没有任何的封装,直接面对业务逻辑的话,业务逻辑编写者显然需要知道如何获取诸如客户基本资料、客户扩展资料等持久对象的。 你当然可以提供诸如持久对象工厂之类的来生成客户基本资料、客户个性化资料等持久对象。但是针对业务逻辑编写者来讲。仅仅拿到这些对象的过程通常来讲是比这要复杂的。一个业务对象(大部分情况是值对象)由哪些持久对象抽取属性来构造,一种情况是通过严格的主-外键关系来自动获取。(Robbin似乎又要说我了,这里看不到表的。)不如说是持久对象的OID。另一种情况就是完全由业务特性决定,没有任何对象的OID关联关系。 如果你做了从持久对象的获取、组装的操作。其实就是完成了DTO的功能。这个功能统一封装。也业务的粒度提供。就是值对象-持久对象Mapping的应用。 Robbin,就DTO。不知道你有何看法? |
|
返回顶楼 | |
发表时间:2004-12-02
嗯,用法比较新鲜......
|
|
返回顶楼 | |
发表时间:2004-12-02
不如拿一个具体的例子来说吧,这样抽象的争论下来没有结论的。
|
|
返回顶楼 | |
发表时间:2004-12-03
po不就是业务对象最原始直观的表示咯。
引用 业务看到的数据通常是各个持久对象的聚合 ,po的聚合还是po啊!你说的把几个po聚合在一起做为一个业务对象,真正的意思无非是facade模式,让api看起来干净些,统一些而已。
不过呢,为什么要这个facade模式呢,为什么不直接的体现po间的协作呢?既然po们关联上了,那么它们的逻辑也总是从某一po开始. dto可以故名思义怎么又把业务对象跟它混合起来呢。 |
|
返回顶楼 | |
发表时间:2004-12-03
呵呵,那我就以实际的例子来看吧。一个简单的客户资料的部分类图参考附件。从静态类图来讲,通常我们会直接映射到数据库中。即针对客户的资料。我们会构建客户基本资料表、客户个性化资料表、客户的亲情表等。当然,从对象的角度你只看到这些持久对象。
针对一个客户的操作行为,比如“创建客户”,我们界面的输入粒度是根据业务逻辑来进行的,会同时提供三个持久对象的信息。在通常的架构设计里,会考虑把这些信息以值对象的方式传递到业务逻辑。下面看如果没有DTO,我们业务逻辑会怎样来创建客户资料呢? session = sessionFactory.getSession();; CustBaseInfoPO baseInfoPO = new CustBaseInfoPO ();; //采用自动化工具把值对象里的值转化到持久对象里。 BeanUtil.copyProperty(vo,baseInfoPO );; session.save(baseInfoPO );; PersonalityPO personalityPO = new PersonalityPO ();; //采用自动化工具把值对象里的值转化到持久对象里。 BeanUtil.copyProperty(vo,personalityPO );; session.save(personalityPO );; RelativePO rlativePO = new RelativePO ();; //采用自动化工具把值对象里的值转化到持久对象里。 BeanUtil.copyProperty(vo,rlativePO );; session.save(rlativePO );; session.flush();; 如果你实现了DTO,以业务逻辑的值对象粒度来提供数据访问接口的话。代码简化为: DataAccess dataAccess = new HibernateDataAccess();; dataAccess.createByValue(vo);; 另外,个人感觉采用DTO以后,DataAccess 作为DTO的抽象接口,允许有不同的实现,在我的一个具体实现里,就包括了ORM的Hibernate的实现和JDBC的实现(为了性能)。这样在你想切换实现的时候可以采用工厂方法等技术来实现各个实现之间的透明切换。这点非常适用于大型系统,当你测试发现某些实现采用Hibernate性能不够的时候,可以不用修改业务逻辑来进行动态数据访问的策略切换。(配置文件) |
|
返回顶楼 | |
发表时间:2004-12-03
NO VO, NO DTO, only one domain object:
CustBaseInfo info = new CustBaseInfo();; info.setName("Readonly");; info.setRelatives(relatives);; session.save(info);; //hibernate will help you to cascade update all |
|
返回顶楼 | |
发表时间:2004-12-03
引用 NO VO, NO DTO, only one domain object: java代码: CustBaseInfo info = new CustBaseInfo();; info.setName("Readonly");; info.setRelatives(relatives);; session.save(info);; //hibernate will help you to cascade update all 领域模型对象是不能完全用这种方式实现的,当从业务的角度一个业务模型对象需要从几个有对象关系的持久对象获取数据的时候,OK。这个没有问题,工作的很好,但是当你需要从没有直接对象关系的持久对象抽取数据构造业务对象的时候。这种方式就很难处理了。 |
|
返回顶楼 | |
发表时间:2004-12-03
tuskrabbit 写道 领域模型对象是不能完全用这种方式实现的,当从业务的角度一个业务模型对象需要从几个有对象关系的持久对象获取数据的时候,OK。这个没有问题,工作的很好,但是当你需要从没有直接对象关系的持久对象抽取数据构造业务对象的时候。这种方式就很难处理了。 楼上这句话说到DO问题的点子上了 DO在维护存在静态关联的对象时确实存在这样的问题 但是无静态关联的对象有可能需要共同合作构造业务对象吗? 如果有这样的需求的例子,能不能举一个出来? 你前面举得例子说的都是有静态关联关系的对象的例子 (客户->客户亲情->客户资料) E-R方式和DO方式都是在建模时考虑了对象或实体间的关系 如果两个实体或对象间存在关系,为什么不在建模时建立关联呢? 如果你真的遇到过这个问题,给俺讲讲吧 |
|
返回顶楼 | |