锁定老帖子 主题:为什么我的程序传递DTO
该帖已经被评为精华帖
|
|
---|---|
作者 | 正文 |
发表时间:2006-03-20
partech 写道 firebody 写道 早点放出这个图就好了。 哈哈。
看到这个图,我明了你的设计意图了。 在Client段通过Remote,直接调用服务端的接口 ,这样的话,DTO的设计就是比较合理的。 整个架构设计很清晰,也是很合理的。 后面的DTO assember在清晰的架构下,也是可以接受的。 可能我一直没有接触到RIA C/s开发模式,其实我前面的讨论一直是B/s的设计遗毒,有点空对空了。 不过,在这个架构的基础上,引入我上面所说的平面数据/数据转换层的设计,不知道会不会在整体架构上会有一个提高就很难说了。我有时间会继续关注这个问题,如果引入我这个设计的话,这样的一个设计会有什么优缺点呢? 对比与上图的DTO模式,一个精巧的类似webwork的模式引入到Server端的Service实现,这样是否会更好一些呢? 讨论一下。。。 我不清楚是否是因为基于B/S结构的程序,表示层在Server上有部分代码,所以没用注意划分表示层和Service层的边界。 实际上,上面的结构在不是RichClient,不需要Remoting的情况下,同样适用。服务层接口明确的定义了,服务层的职责,表示层通过服务接口提供的服务来实现,交互逻辑,提供界面展示,对于RCP或AJAX模式,表示层进而又可以划分为两个子层View,PresentationModel。这是另外一个话题,这里就不展开了。 从Service层关联的上下两层,可以看出,Service层的职责,就是在Domain层边界,处理那些不属于业务范畴的相关事宜,包括:将表示层的业务调用,委托给相应的DomainObject。负责双向的数据转换(包括异常的转换),处理事务等。数据转换是一个相对独立的职责,并且,多个Service中可能包含相同的转换,所以才出现了assembler。 你引入的扩展,俺还不甚明了。文件给你。show一下你的idea吧。 我这里没有Viso ,只能用文字大概描述一下了。 将Xwork的整体设计引入到你的Server端的Service实现,一个统一的入口Service,作专门的Request Dispatcher,就象Webwork的入口Servlet一样,具体的完成客户端某个请求的动作是由Action来完成的。 Xwork已经提供了整体的设计和扩展,Action的运行结果以Result为扩展接口,我们这里的Result一般是一个XML摸板,填充摸板的数据(也就是PO)由Action提供或者也可以PO数据直接放到摸板上下文中,生成的XML数据直接通过IO接口发回客户端。 我想这样的设计思路,曹晓刚或者Dlee他们应该更有发言权,我也是天马行空的想了一下。 整体的边界的输入输出都是XML。 如果你你没有看过Xwork/ognl的结合,我这里具一个简单的例子: 一个更新User的请求: <Request actionId="updateUser"> <field name="userId">1</field> <field name="user.userName">newName</field> <field name="user.age">13</field> </Request> 数据转换层职责就是Parse这个请求XML报文,ActionDispatcher根据actionId定位到这么一个Action: class UpdateUserAction implements Action{ private User user; private String userId; private UserService userService; public void setUserId(String userId);{ this.user= userService.findUserById(usertId);: } public User getUser();{ return this.user; } public string execute();{ this.userService.updateUser(user);; return "success"; } } 实例一个Action对象,然后通过OGNL将请求参数自动设置到Action中,一个动作自动执行序列如下: action.setUserId(1);; action.getUser();.setUserName("newName");; 最后通过一些列的Xwork拦截器调用之后,执行 action.execute();. 返回Success,根举返回的result String,找到定义的摸板,再以这个执行完动作的Action实例作为template的Context,声称结果XML。 |
|
返回顶楼 | |
发表时间:2006-03-21
firebody 写道 我这里没有Viso ,只能用文字大概描述一下了。
将Xwork的整体设计引入到你的Server端的Service实现,一个统一的入口Service,作专门的Request Dispatcher,就象Webwork的入口Servlet一样,具体的完成客户端某个请求的动作是由Action来完成的。 Xwork已经提供了整体的设计和扩展,Action的运行结果以Result为扩展接口,我们这里的Result一般是一个XML摸板,填充摸板的数据(也就是PO)由Action提供或者也可以PO数据直接放到摸板上下文中,生成的XML数据直接通过IO接口发回客户端。 我想这样的设计思路,曹晓刚或者Dlee他们应该更有发言权,我也是天马行空的想了一下。 整体的边界的输入输出都是XML。 如果你你没有看过Xwork/ognl的结合,我这里具一个简单的例子: 一个更新User的请求: <Request actionId="updateUser"> <field name="userId">1</field> <field name="user.userName">newName</field> <field name="user.age">13</field> </Request> 数据转换层职责就是Parse这个请求XML报文,ActionDispatcher根据actionId定位到这么一个Action: class UpdateUserAction implements Action{ private User user; private String userId; private UserService userService; public void setUserId(String userId);{ this.user= userService.findUserById(usertId);: } public User getUser();{ return this.user; } public string execute();{ this.userService.updateUser(user);; return "success"; } } 实例一个Action对象,然后通过OGNL将请求参数自动设置到Action中,一个动作自动执行序列如下: action.setUserId(1);; action.getUser();.setUserName("newName");; 最后通过一些列的Xwork拦截器调用之后,执行 action.execute();. 返回Success,根举返回的result String,找到定义的摸板,再以这个执行完动作的Action实例作为template的Context,声称结果XML。 如果PO都是在Action中修改完成,那么留给Service和Domain层的还有多少东西呢? 如此一个修改用户的服务,我会在Service后面或Domain中,处理修改PO的业务逻辑,简化版本的实现如下: public interface IUserService{ void updateUser(String id,String name,int age...);; } public class UserService implements IUserService{ public void updateUser(String id,String name,int age...);{ User user = User.getFinder();.findById(id);; user.setName(name);; user.setAge(age);; ...... } } 然后在Service方法上通过AOP辅以事务,就完成了,简化版本的业务。 下图是Service层应对WebService的Wrapper版本设计。正如你前面提到的方法,可以通过OGNL、CG或反射的方式,来编写通用的转化。一一对应的关系,甚至连一行配置都不需要。 |
|
返回顶楼 | |
发表时间:2006-03-21
partech 写道 firebody 写道 我这里没有Viso ,只能用文字大概描述一下了。
将Xwork的整体设计引入到你的Server端的Service实现,一个统一的入口Service,作专门的Request Dispatcher,就象Webwork的入口Servlet一样,具体的完成客户端某个请求的动作是由Action来完成的。 Xwork已经提供了整体的设计和扩展,Action的运行结果以Result为扩展接口,我们这里的Result一般是一个XML摸板,填充摸板的数据(也就是PO)由Action提供或者也可以PO数据直接放到摸板上下文中,生成的XML数据直接通过IO接口发回客户端。 我想这样的设计思路,曹晓刚或者Dlee他们应该更有发言权,我也是天马行空的想了一下。 整体的边界的输入输出都是XML。 如果你你没有看过Xwork/ognl的结合,我这里具一个简单的例子: 一个更新User的请求: <Request actionId="updateUser"> <field name="userId">1</field> <field name="user.userName">newName</field> <field name="user.age">13</field> </Request> 数据转换层职责就是Parse这个请求XML报文,ActionDispatcher根据actionId定位到这么一个Action: class UpdateUserAction implements Action{ private User user; private String userId; private UserService userService; public void setUserId(String userId);{ this.user= userService.findUserById(usertId);: } public User getUser();{ return this.user; } public string execute();{ this.userService.updateUser(user);; return "success"; } } 实例一个Action对象,然后通过OGNL将请求参数自动设置到Action中,一个动作自动执行序列如下: action.setUserId(1);; action.getUser();.setUserName("newName");; 最后通过一些列的Xwork拦截器调用之后,执行 action.execute();. 返回Success,根举返回的result String,找到定义的摸板,再以这个执行完动作的Action实例作为template的Context,声称结果XML。 如果PO都是在Action中修改完成,那么留给Service和Domain层的还有多少东西呢? 如此一个修改用户的服务,我会在Service后面或Domain中,处理修改PO的业务逻辑,简化版本的实现如下: public interface IUserService{ void updateUser(String id,String name,int age...);; } public class UserService implements IUserService{ public void updateUser(String id,String name,int age...);{ User user = User.getFinder();.findById(id);; user.setName(name);; user.setAge(age);; ...... } } 然后在Service方法上通过AOP辅以事务,就完成了,简化版本的业务。 下图是Service层应对WebService的Wrapper版本设计。正如你前面提到的方法,可以通过OGNL、CG或反射的方式,来编写通用的转化。一一对应的关系,甚至连一行配置都不需要。 从上图我更加困惑,甚至怀疑我们的交流是否互相误解。 我所提到的引入Xwork/XML框架优势之一就是消除DTO的引入,但是看了你的上图,既说引入OGNL和XML,又在后面引入DTO作为数据载体,Assembler的代码仍然充斥其中,如果是这样,那还不如直接用DTO好了。 引入Xwork之后,Service只依赖于PO也就是领域模型实体。 这里可能有些概念冲突,在你的设计中,Service是充当Facade的作用的,而我这里可能与你的Service同等概念的是 :Action 。 另外,对于你的原来Service依赖的DTO,现在已经转为XML,你的设计需要对DTO进行Assemler(DTO--->PO) ,对应的,Xwork的设计(XML--->PO),这个转换过程是在数据转换层自动完成的。 这样依赖,就省掉了DTO的设计和引入DTO Assembler的设计。 |
|
返回顶楼 | |
发表时间:2006-03-21
firebody 写道 从上图我更加困惑,甚至怀疑我们的交流是否互相误解。
我所提到的引入Xwork/XML框架优势之一就是消除DTO的引入,但是看了你的上图,既说引入OGNL和XML,又在后面引入DTO作为数据载体,Assembler的代码仍然充斥其中,如果是这样,那还不如直接用DTO好了。 赫赫,哪有那么多误解? 没错service后面的assembler可以采用Xwork/XML的方式来实现。 但是,Client就一定要接受XML吗?在都是java的环境下,直接传递java对象,会更有效率。由于采用XML接口的Client(如AJAX),不过是调用的机制不同而已。所以可以简单的,把从java接口的调用转化为XML的调用。 下图中,后台服务,同时可以支持多种访问途经。 |
|
返回顶楼 | |
发表时间:2006-03-21
partech 写道 firebody 写道 从上图我更加困惑,甚至怀疑我们的交流是否互相误解。
我所提到的引入Xwork/XML框架优势之一就是消除DTO的引入,但是看了你的上图,既说引入OGNL和XML,又在后面引入DTO作为数据载体,Assembler的代码仍然充斥其中,如果是这样,那还不如直接用DTO好了。 赫赫,哪有那么多误解? 没错service后面的assembler可以采用Xwork/XML的方式来实现。 但是,Client就一定要接受XML吗?在都是java的环境下,直接传递java对象,会更有效率。由于采用XML接口的Client(如AJAX),不过是调用的机制不同而已。所以可以简单的,把从java接口的调用转化为XML的调用。 下图中,后台服务,同时可以支持多种访问途经。 从你的设计来看,我觉得我们对待这个问题还是有不同的设计的。 其实说到底,就是不用DTO,而是使用XML。这么一个核心的区别。 你后面提供的图,说白了就是你原来的设计框架+加上一个XML Assembler。 核心还是以DTO为主要数据载体,不同的接口都是在DTO和外部数据之间做转换。 如果这是一个已有系统的改造,毫无疑问,这是可行的。 但是如果是一个全新的设计,我觉得我们讨论的重点就在于是否使用DTO。 我不知道我所提到的观点和论据,你是否有更多额辩解 。 |
|
返回顶楼 | |
发表时间:2006-03-21
firebody 写道 从你的设计来看,我觉得我们对待这个问题还是有不同的设计的。 其实说到底,就是不用DTO,而是使用XML。这么一个核心的区别。
你后面提供的图,说白了就是你原来的设计框架+加上一个XML Assembler。 核心还是以DTO为主要数据载体,不同的接口都是在DTO和外部数据之间做转换。 如果这是一个已有系统的改造,毫无疑问,这是可行的。 但是如果是一个全新的设计,我觉得我们讨论的重点就在于是否使用DTO。 我不知道我所提到的观点和论据,你是否有更多额辩解 。 是的,我同意你对我的方案的看法。那不过是一个简单的封装。 要说到差别,上面我问了一个问题,“是否Client端就一定要用XML呢”? 从效率的角度上看,基于XML的调用,大概会比直接传递javaDTO对象,慢一个数量级。虽说XML确实有它的好处,但缺点也同样明显。另外,如果是java客户端,不可避免,在客户端,还需要再解析为javaDTO,如果不转换,java中直接使用XML,方便性就会大打折扣。 如果,你认为传递XML方式在任何情况下,都能够满足要求,那么,不使用javaDTO,也没啥不可。 使用javaDTO,在效率和编程一致上,确实是有优势的。 另外,一个差别就是对service的使用,我确实看不出你把部分业务代码放到Action里面,有啥额外的好处。 |
|
返回顶楼 | |
发表时间:2006-03-21
partech 写道 firebody 写道 从你的设计来看,我觉得我们对待这个问题还是有不同的设计的。 其实说到底,就是不用DTO,而是使用XML。这么一个核心的区别。
你后面提供的图,说白了就是你原来的设计框架+加上一个XML Assembler。 核心还是以DTO为主要数据载体,不同的接口都是在DTO和外部数据之间做转换。 如果这是一个已有系统的改造,毫无疑问,这是可行的。 但是如果是一个全新的设计,我觉得我们讨论的重点就在于是否使用DTO。 我不知道我所提到的观点和论据,你是否有更多额辩解 。 是的,我同意你对我的方案的看法。那不过是一个简单的封装。 要说到差别,上面我问了一个问题,“是否Client端就一定要用XML呢”? 从效率的角度上看,基于XML的调用,大概会比直接传递javaDTO对象,慢一个数量级。虽说XML确实有它的好处,但缺点也同样明显。另外,如果是java客户端,不可避免,在客户端,还需要再解析为javaDTO,如果不转换,java中直接使用XML,方便性就会大打折扣。 如果,你认为传递XML方式在任何情况下,都能够满足要求,那么,不使用javaDTO,也没啥不可。 使用javaDTO,在效率和编程一致上,确实是有优势的。 另外,一个差别就是对service的使用,我确实看不出你把部分业务代码放到Action里面,有啥额外的好处。 如果是这样的设计架构的话,那么客户端就没必要再转换为JavaDTO了,客户端的数据模型就是以XML为主了,至于说java parse XML接口会不会带来开发的方便性,我觉得这是很片面的观点。 如果作为一个架构的设计的话,我想你们开发组会专门封装一个read/write XML的接口的,这样的接口易用性的设计就是负责开发这个接口的设计的问题了。 |
|
返回顶楼 | |
发表时间:2006-03-21
firebody 写道 如果是这样的设计架构的话,那么客户端就没必要再转换为JavaDTO了,客户端的数据模型就是以XML为主了,至于说java parse XML接口会不会带来开发的方便性,我觉得这是很片面的观点。 如果作为一个架构的设计的话,我想你们开发组会专门封装一个read/write XML的接口的,这样的接口易用性的设计就是负责开发这个接口的设计的问题了。
虽然,一些混合java类和XML的编程方式,在不断的吸引我们的眼球,但我不认为,已经达到了无缝结合的地步。表示层,使用XML,不仅仅只是读写,比如:数据绑定问题如何解决?如果你认为XML可以媲美于java对象的使用,那俺也没啥好说的。另外,效率方面的问题,可以完全忽略麽? 前阵子研究了一下,基于EMF实现的SDO,结构很小,很优美。但对SDO的支持,却少得可怜。 如果,SDO哪天,能够满足我的各种要求,那么我会毫不犹豫地抛开javaDTO,投向SDO的怀抱。但在这之前,javaDTO就是我的选择。 http://java.sys-con.com/read/46652.htm |
|
返回顶楼 | |
发表时间:2006-03-21
partech 写道 firebody 写道 如果是这样的设计架构的话,那么客户端就没必要再转换为JavaDTO了,客户端的数据模型就是以XML为主了,至于说java parse XML接口会不会带来开发的方便性,我觉得这是很片面的观点。 如果作为一个架构的设计的话,我想你们开发组会专门封装一个read/write XML的接口的,这样的接口易用性的设计就是负责开发这个接口的设计的问题了。
虽然,一些混合java类和XML的编程方式,在不断的吸引我们的眼球,但我不认为,已经达到了无缝结合的地步。表示层,使用XML,不仅仅只是读写,比如:数据绑定问题如何解决?如果你认为XML可以媲美于java对象的使用,那俺也没啥好说的。另外,效率方面的问题,可以完全忽略麽? 前阵子研究了一下,基于EMF实现的SDO,结构很小,很优美。但对SDO的支持,却少得可怜。 如果,SDO哪天,能够满足我的各种要求,那么我会毫不犹豫地抛开javaDTO,投向SDO的怀抱。但在这之前,javaDTO就是我的选择。 http://java.sys-con.com/read/46652.htm 操纵XML确实没有Object要来的直接。 如果要达到直接数据绑定,可能这对客户端XML接口设计的要求比较高。 你说的数据绑定的难题,可以举个例子吗? 效率方面的问题,我认为跟你选择Parser很有关系,我推荐使用SaxParser,不过性能一般不会很差。 |
|
返回顶楼 | |
发表时间:2006-03-21
firebody 写道 操纵XML确实没有Object要来的直接。 如果要达到直接数据绑定,可能这对客户端XML接口设计的要求比较高。
你说的数据绑定的难题,可以举个例子吗? 效率方面的问题,我认为跟你选择Parser很有关系,我推荐使用SaxParser,不过性能一般不会很差。 就像http://www.martinfowler.com/eaaDev/PresentationModel.html里面描述的绑定。View同PresentationModel之间的绑定。即使采用ajax,我同样可以采用PresentationModel的结构。 效率不光在解析上,比较一下Remoting的效率,差别是明显的。 |
|
返回顶楼 | |