精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2005-03-14
jackyz 写道 这个 Implement 会调用远程 Session 服务的包装接口,获取所需的对象(这个过程对于外部代码会是透明的)。
这句话已经很明确无误的否定了你自己的设想了。Hibernate是一个底层框架,不是一个常驻内存的服务,或者用我们流行的用语来说,叫做容器。如果Hibernate企图去做这种分布式的应用,它就不是一个ORM,而是演变成了一个支持远程访问的容器了。 而支持远程访问的容器这并不是Hibernate要做的事情,是SpringFramework,是EJB3要做的事情。打个比方来说,你是销售经理,我是软件架构师,你负责和客户打交道,打单,而我负责领导软件开发团队开发,设计软件架构。 这个时候你突然说软件开发和客户之间的距离太远了,我们必须让架构师具备销售经理的素质和能力,让架构师去整天跑客户,打单,陪客户吃饭,这不是本末倒置吗? 作为一个ORM来说,即使不考虑到远程调用,其实也有很多的功能需要在ORM之外来解决,例如数据库资源的透明化管理,例如抽象的声明式事务管理,例如合理的异常层次设计和异常处理方式,例如合理的Dao接口隔离等等等等。这些工作都是必须在ORM之外来完成的。ORM是一个相当底层的框架,它需要运行在一个受控的管理环境中(managed Environment),而上面提到的这些功能都是由这个受控的管理环境来实现的,而且包括你提到远程调用问题,实际上也是未来受控环境应该提供的功能之一。 目前来说,SpringFramework实际上就是这个受控的管理环境,他处理了ORM上层的数据库资源透明的管理,容器可声明的事务管理,异常的处理流程和事务回滚等等。当然,Spring目前对远程调用的支持还很不成熟,实际上对远程调用的支持也是我最期待Spring改进的方面。 就未来展望,EJB3实际上就是你期望的东西,EJB容器提供了这个受控的管理环境,当然继承自EJB2的远程调用也会得到很好的支持,而基于Hibernate的EJB3持久化标准也提供了类似Hibernate的ORM功能,不过会在远程调用上提供了透明的支持。 所以基本上可以这样来对比: Spring+Hibernate vs EJB3 Spring和Hibernate合在一起才有能和EJB3相提并论的比较基础,即都提供了一个完整的企业应用基础设施。他们的区别则是面向不同的市场。 |
|
返回顶楼 | |
发表时间:2005-03-14
jackyz 写道 再仔细思考了一遍,为什么我希望在Client使用PO(或者DomainObject)?我之所以希望能够在Client端有DomainObject,主要是因为——我自己既写后端代码又写前端代码——对于我来说,在Client端直接使用DomainObject,不仅功能丰富,而且无需处理和DomainObject“高度类似”的DTO的生成和转换的问题(DTO代码怎么着都让人有种和DomainObject重复的感觉)。 对于你说的小型项目开发人员同时负责前后台的情况,你认为对于只需要传递三个属性的情况下,却传递了几十个属性合理吗? 更极端的情况是“获取客户列表”,这时仅仅需要包含客户代码和客户姓名两个属性的VO集合。直接传递PO将会传递客户的集合过来。 另外,关于DomainObject同DTO“高度类似”的问题。 不知道我说的对不对,你之所以感觉重复是因为你的DomainObject中 没有包含本来该封装在它里面的业务逻辑。 来做一个类比吧: DomainObject中的Class同影射到数据库中的表也是“高度类似”吧。 某种意义上说DomainObject到数据库表的映射同到DTO的映射都是 对象在不同环境的不同表示而已。 从关系数据库的观点来看,他把对象看作表中的行。到了业务层它变成了 一个个的DomainObject。到了应用层它又变成了面向用户的信息。针对 不同的环境需要有不同的表示,这也意味着要经过不同的变换。 就拿数据库来说吧。数据库里面的表大多数情况下是不能直接给用户查看的。 要不报表这种东西就完全没有必要了。数据库的数据需要收集、抽取、转换、 计算等处理后才能得到报表需要的信息,呈现在用户面前。 如果让前台开发人员直接使用PO,那无异于让用户直接查看数据库中的表。 是的,如果你开发的系统自己就是用户,那么查询的功能确实完全可以不要, 自己到数据库的表里找就是了,呵呵。不过即使是这种情况,你也会借助SQL 来转化数据。而不会一个表一个表的查找。 扯得远了点,明白我的意思了吗? |
|
返回顶楼 | |
发表时间:2005-03-14
引用 如果让前台开发人员直接使用PO,那无异于让用户直接查看数据库中的表
这说明你还不懂ORM。 关于DTO的话题,论坛已经讨论的过多了,只怕有上千帖了吧,我看没有必要再讨论一遍了。要讨论DTO,先去翻翻以前的讨论,如果没有新的观点,还是打住吧。 |
|
返回顶楼 | |
发表时间:2005-03-14
robbin 写道 引用 如果让前台开发人员直接使用PO,那无异于让用户直接查看数据库中的表
这说明你还不懂ORM。 关于DTO的话题,论坛已经讨论的过多了,只怕有上千帖了吧,我看没有必要再讨论一遍了。要讨论DTO,先去翻翻以前的讨论,如果没有新的观点,还是打住吧。 呵呵,没看见吗?前面说得很清楚,这是一个类比。 没错,是讨论了很多。人家都说了是在炒冷饭没看见? 同时我并没有看到支持直接传递PO的有力证据,您老有给出过吗?同样反对DTO的理由也不充分,最多的就是嫌麻烦。 你如果不感兴趣,或者认为自己的观点已经没有什么需要阐述的了,那就让我这个不懂ORM的人同人家炒炒冷饭好吗? 您老就高抬贵手吧。 |
|
返回顶楼 | |
发表时间:2005-03-15
Shit,写了一大段,竟然丢了要重写,苦死我了。:?
robbin 写道 Hibernate是一个底层框架,不是一个常驻内存的服务,或者用我们流行的用语来说,叫做容器。如果Hibernate企图去做这种分布式的应用,它就不是一个ORM,而是演变成了一个支持远程访问的容器了。
嗯,我知道这不是ORM的职责,也没有期望Hibernate能做这件事。 实际上,用Spring也好, EJB3也罢,或者上面提到的“Hack Hibernate CGLIB Process”,甚至是手写代码加上Factory,Servlet,Serializable也能实现一个这样的“透明RPC框架”,如何实现其实并不是问题的关键。 这个冷饭贴,实际上是我的突发奇想。论证一个突发奇想也许并不是为了证明它或者实现它,即使最后的结论是“这真是一个无聊的想法”,但在它的论证过程中,我们也许能更清楚“Why It's EVIL”。我的Point在于模式的选择,在Remote场景,在我们期待的RIA时代,除了DTO模式,除了被裁减的PO,难道我们就确实没有其他的选择了? 是的,partech,我知道你说得很有道理,DTO允许前后台并行开发(这似乎是一个致命优点);我也知道我的DomainObject设计得很烂,它们不Rich,缺少太多的业务逻辑;而且,因为没有其他成熟方案,我目前的项目也必须采用DTO。但,“展开想象的翅膀”,权当做个白日梦,总是可以的吧。 partech 写道 反对DTO的理由也不充分,最多的就是嫌麻烦。
嫌麻烦难道不是一个很好的理由么?很多人就是因为嫌麻烦而不愿意使用DTO(包括我 )。DTO被大家众口一词的诟病,难道他们都是人云亦云?EJB确实是失败了(WithOut EJB Patterns),但这是否能够说明它的设计思路就是一无是处呢? 一个不可否认的事实是——DTO的引入,实际上造成系统中出现了两个(或者说N个)对象体系——Server端面对的是Rich的DomainObject,Client端面对的是Flat的DTO。我实在是搞不明白,一个高度面向对象的系统中,为什么要有多个对象体系呢?仅仅是为了传输? 就拿这个例子来说: partech 写道 数据库里面的表大多数情况下是不能直接给用户查看的。
要不报表这种东西就完全没有必要了。数据库的数据需要收集、抽取、转换、计算等处理后才能得到报表需要的信息,呈现在用户面前。 数据库的数据需要收集、抽取、转换、计算可以交给DAO,那么,呈现又为什么不能交给RemoteClient呢? 单就呈现这部分而言,如果引入DTO,服务端要做的实际上就是“从DomainObject中取出需要的属性,塞入DTO中”,然后传输,RemoteClient端做的就是“从DTO中取出需要显示的值,放到相应的Widgets中”,多么令人乏味的工作? 如果传来的直接就是DomainObject(当然,这里没有考虑传输代价),由RemoteClient来负责“从DomainObject中取出需要的属性,放到相应的Widgets中”,这又有何不可?至于具体的显示,直接调用方法或者ONGL,那不会是个大问题。更重要的是,无论在系统的前端还是后端,我所理解的是一个统一的对象体系。 去掉了DTO,也就可以不管它的生产、转换、组装、传输、消费……。对于有着“懒惰这个优良品质”的程序员来说,能省的,就别留着,不是么? ok,问题时间。 问题一,变化。让DomainObject跨越系统的所有层次,对它的修改必然困难重重,但我们也不在石器时代,Refactor工具至少能让人的体力劳动能轻松点。况且,修改接口也并非闻所未闻的事嘛。 问题二,并行。没有DTO的隔离,前后端的开发难于并行进行,是的,的确难于,但也许并非是不可能的吧,Mock是否有助于此呢?堂堂DomainObject至少也得有个Interface才象话吧。 问题三,浪费。确实,我强买强卖地带了很多“用不上的属性”(至少目前用不上),虽说,我们可以LazyLoad,我们有LocalCaching,但的确浪费了一些宝贵的带宽,罪过罪过。但,比起“设计和维护N个DomainObject在M种情况下的各个DTO”,也许我可以选择——认了。 问题四,做梦。不要忘了,所有美丽的幻象都是建立在“不考虑传输代价”的空中楼阁之上——谁说不是呢?不过,也许某天有位GavinKing之类的大仙“一不小心踩到香蕉皮”帮俺们解决这个问题了呢(LazyLoad可以得到Fullfeature的PO和合理的传输粒度,Caching可以减少RPC的次数)?且让我再梦一会儿吧。 …… 共产主义还未实现,进度总是在生气,DTO仍然要继续。 梦总是要醒的,生活是残酷地~~ |
|
返回顶楼 | |
发表时间:2005-03-15
jackyz 写道 嫌麻烦难道不是一个很好的理由么?很多人就是因为嫌麻烦而不愿意使用DTO(包括我 )。DTO被大家众口一词的诟病,难道他们都是人云亦云?EJB确实是失败了(WithOut EJB Patterns),但这是否能够说明它的设计思路就是一无是处呢? 一个不可否认的事实是——DTO的引入,实际上造成系统中出现了两个(或者说N个)对象体系——Server端面对的是Rich的DomainObject,Client端面对的是Flat的DTO。我实在是搞不明白,一个高度面向对象的系统中,为什么要有多个对象体系呢?仅仅是为了传输? 单就呈现这部分而言,如果引入DTO,服务端要做的实际上就是“从DomainObject中取出需要的属性,塞入DTO中”,然后传输,RemoteClient端做的就是“从DTO中取出需要显示的值,放到相应的Widgets中”,多么令人乏味的工作? 如果传来的直接就是DomainObject(当然,这里没有考虑传输代价),由RemoteClient来负责“从DomainObject中取出需要的属性,放到相应的Widgets中”,这又有何不可?至于具体的显示,直接调用方法或者ONGL,那不会是个大问题。更重要的是,无论在系统的前端还是后端,我所理解的是一个统一的对象体系。 去掉了DTO,也就可以不管它的生产、转换、组装、传输、消费……。对于有着“懒惰这个优良品质”的程序员来说,能省的,就别留着,不是么? 呵呵,我相信假如你看到这种转化是必须的,那么不管它是否麻烦你都会乐此不疲的使用,就像使用Hibernate一样。 为了说清楚我的观点,你需要同我一起上升到1千米的空中来审视所开发的系统。 从前向后看是三个领域,分别是应用、服务和数据库。在服务和数据库之间使用ORM大家都很熟悉 可以为什么不能把DomainObject直接持久化到数据库呢?问题就在于两者看待信息的观点不同。 服务层包裹中的业务层是数据和行为封装在一起的业务对象。关系型数据库中的信息是表中的行。 同样的应用层负责同用户交互,它的观点就是用例的观点,能够很好匹配的模式就是输入是什么,系统状态如何变化,输出是什么。 应用层的方方面面无不是围绕他们展开的,输入的是Action,系统状态变化被抽象为Model,输出的是View。 在用例中你不会看到有关业务对象如何实现的描述,这要到设计业务层才会考虑。但是仅仅需要这些信息就完全能够 设计出应用层需要服务层完成的接口了。这时候业务层还未设计出来,所以设计成传递PO的服务层接口是完全不可能的。 相反设计出传递VO符合用例的服务接口则是唾手可得的事情。我们反过来看看传递PO的不合理。服务接口是基于用例的, 对于显示客户信息的段落我们可以这样描述: 用户输入客户代码,系统确认客户代码有效,系统显示客户的基本信息,包括客户代码、客户姓名、客户证件类型、客户证件号码和客户的状态。 对应的接口方法为 CustomerBasicInfo OnCustomerCodeInput(String customerCode); public class CustomerBasicInfo { public String Code; public String Name; public String CertificateType; public String CertificateNO; public String Status; } 如果采用传递PO则变为 Customer OnCustomerCodeInput(String customerCode); 问题在于Customer对象现在根本无法定义。而且因为业务层还未开发出来,不可避免的开发业务层的过程中会造成接口的不稳定,同时 如果需要重构业务层的话,应用层也不得不被迫重构。 《敏捷软件开发中》里有这样一个开发原则,具体的依赖抽象的,朝稳定的方向依赖。直接传递PO是一个反例。 Hibernate是一种ORM,本质上就是一种转换,把数据库的行转化为DomainObject,或者相反。DTO的Assembler做着同样的事情。 为什么没有人对使用ORM提出质疑,却频频觉得编写Assembler麻烦呢? jackyz 写道 数据库的数据需要收集、抽取、转换、计算可以交给DAO,那么,呈现又为什么不能交给RemoteClient呢? 呈现是Client的事情,但是组装DTO是Assembler的事情。 jackyz 写道 ok,问题时间。 问题一,变化。让DomainObject跨越系统的所有层次,对它的修改必然困难重重,但我们也不在石器时代,Refactor工具至少能让人的体力劳动能轻松点。况且,修改接口也并非闻所未闻的事嘛。 请参考Robort Martin的大作《敏捷软件开发中》,频繁修改接口说明依赖关系有问题。 jackyz 写道 问题二,并行。没有DTO的隔离,前后端的开发难于并行进行,是的,的确难于,但也许并非是不可能的吧,Mock是否有助于此呢?堂堂DomainObject至少也得有个Interface才象话吧。 在没有经过艰苦的设计出业务层之前,你的接口中的东东同样是不稳定的。而且你的PO如果简单到同VO差不多,我实在看不出在他上面再来一个接口的必要。 jackyz 写道 问题三,浪费。确实,我强买强卖地带了很多“用不上的属性”(至少目前用不上),虽说,我们可以LazyLoad,我们有LocalCaching,但的确浪费了一些宝贵的带宽,罪过罪过。但,比起“设计和维护N个DomainObject在M种情况下的各个DTO”,也许我可以选择——认了。 浪费带宽其实还是小事。目的不明确才是最根本的。 jackyz 写道 问题四,做梦。不要忘了,所有美丽的幻象都是建立在“不考虑传输代价”的空中楼阁之上——谁说不是呢?不过,也许某天有位GavinKing之类的大仙“一不小心踩到香蕉皮”帮俺们解决这个问题了呢(LazyLoad可以得到Fullfeature的PO和合理的传输粒度,Caching可以减少RPC的次数)?且让我再梦一会儿吧。 呵呵,有没有梦见 XML mm在向你招手微笑?! |
|
返回顶楼 | |
发表时间:2005-03-15
youcai 写道 在我们的设计中,如果组装属性属于业务,会放在DomainObject中,如下 ... public int getStatus(){ return status.getInt(); } ... 如果为了显示,需要组装,有前台自己完成。 对于多余属性,个人不认为会对前台造成什么影响,泄密?使用没有代码完成功能的编辑器? 在我们的设计中,不考虑分布式,基本就不考虑DTO。 嗯,如果你所写的方法是在Customer中,那么恭喜你,你会后很多机会来重构Customer,因为客户签订的协议会与日俱增。 Customer是很底层的业务对象,不要老是去变动它! 多余的属性,会使得你的接口方法变得圆滑,含糊不清。 |
|
返回顶楼 | |
发表时间:2005-03-15
看来我们需要一个DVM了,Domain/View Mapping,根据定义自动将Domain Ojbect转换为View Object。
|
|
返回顶楼 | |
发表时间:2005-03-15
flyisland 写道 看来我们需要一个DVM了,Domain/View Mapping,根据定义自动将Domain Ojbect转换为View Object。
这个想法很好,但是可行性不高,主要是因为Domain Object和View Object的信息量相差太远。如果Domain Object包含的信息量是1的话,那么View Object包含的信息量可能是10,Domain Object只要包含完成任务的信息就足够了,但是View Object是直接面对最终用户的,所以View Object除了需要必需的Domain信息之外,还需要大量的与人机交互相关的信息。诸如层次信息、分组信息、排版信息、交互控制逻辑、事件处理逻辑、数据校验逻辑、帮助信息及提示信息等要素是必不可少的,这些交互控制辅助信息与Domain Object无关,但是却非常重要,客户是否愿意接受系统甚至还取决于这些要素,现在的口号是“科技以人为本”,View Object的复杂程度和重要程度一点都不会逊色于Domain Object。 |
|
返回顶楼 | |
发表时间:2005-03-16
用webwork之类的框架中开发web应用,我们通常的做法就是不用DTO,直接使用PO,View层代码通过ONGL/JSTL来构造界面.大家普遍认可这种做法----因为它的简单方便.而且认为在这种情况下使用DTO是不必要的反模式的.这是目前大家都基本认可的事实.
换一个角度,我们也可以认为,webwork的action程序段就是一个简单的Application,它也处理与用户的交互(一次一个Page),它也与我们的Service层进行交互.也就是说,对Service层而言,它实际上就是一种所谓的"前端代码",所不同的是,这个"前端代码"运行在与Server相同的一个JVM之中. 既然WebWork的"前端代码"直接使用DomainObject是合理的,那么为什么其他的"前端代码"直接使用DomainObject就不合理了呢? 是的,环境不同.不同的JVM,网络传输的代价.除此之外,Service的其他Client无论从哪里来看,与WebWork的Client都没有什么本质的不同. DTO除了Transfer的意义以外,是否并非一种本质上的必须? DTO存在的本质理由是否仅仅就是这种环境的差别? 如果这是DTO存在的本质原因,而且如果引入一种机制能够消除这种差别(或者尽量减少这种差别带来的影响),那么DTO的存在理由是否就不存在了呢? partech 写道 ... 这种转化是必须的,那么不管它是否麻烦你都会乐此不疲的 ... 同样的应用层负责同用户交互,它的观点就是用例的观点,能够很好匹配的模式就是输入是什么,系统状态如何变化,输出是什么。 应用层的方方面面无不是围绕他们展开的,输入的是Action,系统状态变化被抽象为Model,输出的是View。 .... UI的Client与用户交互当然需要MVC,但是,我们是否需要将UI对于Model的需求与DTO的职责混合起来呢? Webwork的开发中Service提供给Action的是DomainObject,我们通常通过Action本身来做转换,得到用于显示的Model.那么,在RichClient的开发中,(如果我们能在代价不高的前提下得到DomainObject)为什么我们就不能这么做呢? // 比如 Client 中的 CustomerInfoWindow // 显示的时候 CustomerInfoWindow 从 CustomerInfoController 中获取相应的值,显示 // CustomerInfoModel (同时也是Controller); 可以是这样的 public class CustomerInfoController { // 用于显示的属性 private String code; private String name; private String certificateType; private String certificateNO; private String status; // 构造器 public UserInfo(String code); { this.code = code; } // 初始化事件 public void onInit(); { // 远程获得Service提供的 CustomerInfo 实例 (DomainObject); CustomerInfo c = service.getCustomerInfo(code);; if (c != null); { // 设置用于显示的值 name = c.getName();; certificateType = c.getCertificate();.getType();; certificateNO = c.getCertificate();.getNO();; status = c.getStatus();.getName();; } } // get and set methods } |
|
返回顶楼 | |