精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2005-03-16
jackyz 写道 用webwork之类的框架中开发web应用,我们通常的做法就是不用DTO,直接使用PO,View层代码通过ONGL/JSTL来构造界面.大家普遍认可这种做法----因为它的简单方便.而且认为在这种情况下使用DTO是不必要的反模式的.这是目前大家都基本认可的事实.
好的,我们来看看你说的大家都认可的事实,会影响程序的那些方面。 1.直接传递PO是否意味着业务层必须要用DomainModel的模式来完成? 这是否意味着你不可能再使用Transaction Script或Table Module的方式来设计, 否则传递的PO本质上就是VO了,一个面向业务VO而不是面向交互的VO。 2.我认为这种模式违反了具体依赖于抽象的原则。看看《敏捷软件开发》中的相关论述好吗? 业务层对象的结构是有可能重构的,比如客户状态的实现。 最初比较简单,设计的结果就是在Customer中添加一个LostReportFlag字段。 public class Customer { ... private boolean lostReportFlag;//挂失标志 ... } 后来发现挂失其实是一种协议,这样需要把它挪出Customer。另外建立一个 协议。 public class LostReportAgreement { ... private Customer customer; private Date createDate; private Date fromDate; private Date toDate; private String remark; ... } 这样原来获取客户状态的getStatus方法就不能放到Customer中了。 直接传递PO意味着客户端也需要做相应的变更。 jackyz 写道 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 } 考虑一下有多个应用的情况,现在客户端除了Web还有RichClient.假如都需要做这种转换,你还认为这种转换是放到Web的Controller类中是一个好的选择吗? 显然,这种转换放到Service层来完成更合理,因为它可以共享多种应用实现相同的部分. |
|
返回顶楼 | |
发表时间:2005-03-16
to partech :
直接传递po(domain object)到view是domain driven design的一种思想,在Transaction Script范畴下探讨它的合理性是没有任何意义的。 如果你想继续讨论,你可以试着在用domain driven design(先设计domain model,在定义业务接口)建模的条件下阐述你的观点。 |
|
返回顶楼 | |
发表时间:2005-03-16
partech 写道 ... 1.直接传递PO是否意味着业务层必须要用DomainModel的模式来完成? 这是否意味着你不可能再使用Transaction Script或Table Module的方式来设计,否则传递的PO本质上就是VO了,一个面向业务VO而不是面向交互的VO。 2.我认为这种模式违反了具体依赖于抽象的原则。看看《敏捷软件开发》中的相关论述好吗? ... 这两个问题我需要再想想,我只知道这么做很便利,目前还不知道这么做违背了多少设计原则. partech 写道 ... 业务层对象的结构是有可能重构的,比如客户状态的实现。 最初比较简单,设计的结果就是在Customer中添加一个LostReportFlag字段。 public class Customer { ... private boolean lostReportFlag;//挂失标志 ... } 后来发现挂失其实是一种协议,这样需要把它挪出Customer。另外建立一个 协议。 public class LostReportAgreement { ... private Customer customer; private Date createDate; private Date fromDate; private Date toDate; private String remark; ... } 这样原来获取客户状态的getStatus方法就不能放到Customer中了。直接传递PO意味着客户端也需要做相应的变更。 的确可能会做这样的重构,那么,如果界面不发生变化,非DTO方案,确实仍然需要更改客户端代码. public class CustomerModel { ... public boolean lostReport; //挂失标志 public void onInit(); { Customer c = service.getCustomer();; lostReport = getLostReportFlag(c);; } // 增加新的转换方法 private boolean getLostReportFlag(Customer c); { Date sysDate = new Date();; LostReportArgreement lra = c.getLostReportAgreement();; if (sysDate.after(lra.getFromDate();); && sysDate.before(lra.getToDate(););); { return true; } else { return false; } } ... } DTO方案,可以不改Client代码,但它也必须要在Service层更改DTO的组装代码.以适应所发生的变化.所做的改动与上门的代码可能极其类似. 而如果界面显示也需要发生变化的时候.DTO方式和非DTO方式相比就没有任何优势----都必须修改前台代码,而且,非DTO的方案,因为没有DTO层,改动甚至要更简单一点. DTO方式所传递的东西其实就是显示中用到的数据,我们认为它就是ViewObject(实际上ViewObject也受限于DTO所定义的方法). 比较两者,区别在于DTO是将DomainObject->ViewObject的Mapping放在Service端,而非DTO将这个过程放在Client端. 问题是,ViewObject本来就是显示逻辑中要用到的东西,为什么在我的Service层也需要关注它呢?仅仅是为了传递? 非DTO方式中,Service对于Client端的功能是不可知的,所以,也无需关注. partech 写道 考虑一下有多个应用的情况,现在客户端除了Web还有RichClient.假如都需要做这种转换,你还认为这种转换是放到Web的Controller类中是一个好的选择吗? 显然,这种转换放到Service层来完成更合理,因为它可以共享多种应用实现相同的部分. 问题是Web的客户端和Rich的客户端对于ViewObject的需求差别太大了,你认为他们之间能够共享相同的ViewObject吗? |
|
返回顶楼 | |
发表时间:2005-03-16
pufan 写道 to partech :
直接传递po(domain object)到view是domain driven design的一种思想,在Transaction Script范畴下探讨它的合理性是没有任何意义的。 如果你想继续讨论,你可以试着在用domain driven design(先设计domain model,在定义业务接口)建模的条件下阐述你的观点。 domain driven design是先设计Domain Model再定义业务接口的意思吗? 谁说domain driven design就一定要传递PO到应用层了? 别蒙我啊,老兄! |
|
返回顶楼 | |
发表时间:2005-03-16
引用 domain driven design是先设计Domain Model再定义业务接口的意思吗?
这也是oo建模的思想啊:先设计domain model,domain model应该厚,有一个业务需求就封装一个薄的service接口给客户端调用,这样可以高效的复用domain model中的逻辑。 引用 谁说domain driven design就一定要传递PO到应用层了?
不是一定,是这样做最优雅。 |
|
返回顶楼 | |
发表时间:2005-03-16
jackyz 写道 的确可能会做这样的重构,那么,如果界面不发生变化,非DTO方案,确实仍然需要更改客户端代码. public class CustomerModel { ... public boolean lostReport; //挂失标志 public void onInit(); { Customer c = service.getCustomer();; lostReport = getLostReportFlag(c);; } // 增加新的转换方法 private boolean getLostReportFlag(Customer c); { Date sysDate = new Date();; LostReportArgreement lra = c.getLostReportAgreement();; //上面c.getLostReportAgreement的设计是有问题的 //因为客户可能会有很多种协议,如果都通过c.getXXXAgreement的方式取得的话。 //因为Customer同协议是使用关系,也就是说是Customer依赖于这些协议,、 //这样稳定的对象就依赖上不稳定的对象了,新的协议会层出不穷。 //这是很大的问题,依赖应该朝着稳定的方向去做而不是相反。 //所以即使要做也该是下面这样: // //LostReportArgreement lostReportAgreement = LostReportArgreementRepository.findbyCustomer(c);; // //Customer对象无论如何都不应当知道直接签订了多少的协议。 // if (sysDate.after(lra.getFromDate();); && sysDate.before(lra.getToDate(););); { return true; } else { return false; } } ... } jackyz 写道 问题是,ViewObject本来就是显示逻辑中要用到的东西,为什么在我的Service层也需要关注它呢?仅仅是为了传递? 非DTO方式中,Service对于Client端的功能是不可知的,所以,也无需关注. Service层负责实现Service层的接口,它当然要输出VO(Value Ojbect -- 不知道你的ViewObject是什么东东?)给应用层用。 Service层对应用层的功能不可知,那它是为谁服务呢?如果你说的是特定的应用层,那么确实Service层对它一无所知。 Service层对可能的所有应用提供统一的服务接口。 jackyz 写道 问题是Web的客户端和Rich的客户端对于ViewObject的需求差别太大了,你认为他们之间能够共享相同的ViewObject吗? SOA的做法,会提供一个统一,一致的服务入口给各种应用。某些应用会用到某些服务,这当中有只有在特定应用用到的服务也有几个应用 共享的服务。 Web客户端和Rich客户端我认为某些VO确实是可以复用的,特别当你在把他们统一考虑的时候。 |
|
返回顶楼 | |
发表时间:2005-03-16
pufan 写道 引用 domain driven design是先设计Domain Model再定义业务接口的意思吗?
这也是oo建模的思想啊:先设计domain model,domain model应该厚,有一个业务需求就封装一个薄的service接口给客户端调用,这样可以高效的复用domain model中的逻辑。 引用 谁说domain driven design就一定要传递PO到应用层了?
不是一定,是这样做最优雅。 呵呵,你的调子是越来越高亚 。不要跑偏了,应当先设计服务接口,Test Driven 否则你花了很长时间做Domain可能最后有些特性服务根本永远不会调用到,或者你不清楚在特定的条件下,那一种Domain Model的设计更优,服务接口的定义会使得设计Domain更有针对性。不是吗? 如果我只是应用层的开发人员,我可没兴趣欣赏后台开发人员开发出来的Domain Model的优雅。我希望看到一个简洁的服务接口。我要什么你就给什么。我才不关心 你的Domain Model的具体结构呢,前台的状态控制就让我够恼火的了。呵呵 |
|
返回顶楼 | |
发表时间:2005-03-16
引用 如果我只是应用层的开发人员,我可没兴趣欣赏后台开发人员开发出来的Domain Model的优雅。我希望看到一个简洁的服务接口。我要什么你就给什么。我才不关心你的Domain Model的具体结构呢,前台的状态控制就让我够恼火的了。 domain model即不属于后台也不属于前台,domain model的设计是在各层划分前实现的,也就是说当domain model的接口确定下来l时系统的层次尚未划分(可能是bs,可能cs,可能是三层也可能是n层),domain model 是在各层之上的,应该贯穿于各层之间。 引用 不要跑偏了,应当先设计服务接口,Test Driven 否则你花了很长时间做Domain可能最有有些特性服务根本永远不会调用到,服务接口的定义会使得设计Domain更有针对性。不是吗?
先定义服务接口还是先建模这应该是transactoin script和domain design的重要区别,建议另开话题,我想会有许多人感兴趣的讨论的。 |
|
返回顶楼 | |
发表时间:2005-03-17
partech 写道 Service层负责实现Service层的接口,它当然要输出VO(Value Ojbect -- 不知道你的ViewObject是什么东东?)给应用层用。 Service层对应用层的功能不可知,那它是为谁服务呢?如果你说的是特定的应用层,那么确实Service层对它一无所知。 Service层对可能的所有应用提供统一的服务接口。 SOA的做法,会提供一个统一,一致的服务入口给各种应用。某些应用会用到某些服务,这当中有只有在特定应用用到的服务也有几个应用 共享的服务。 Web客户端和Rich客户端我认为某些VO确实是可以复用的,特别当你在把他们统一考虑的时候。 Service层的设计应该尽可能的薄,业务逻辑则尽可能的由domain model完成,这样关于前台需要的属性,就看你的设计怎么认为,如果属于业务逻辑,自然设计在domain model内部,就如你举的例子,始终从domain返回状态,至于这个状态是否存在一整套协议对使用domain model的使用者来说是透明的.使用者只需要知道从domain model中获得状态就行了. |
|
返回顶楼 | |
发表时间:2005-03-17
youcai 写道 Service层的设计应该尽可能的薄,业务逻辑则尽可能的由domain model完成,这样关于前台需要的属性,就看你的设计怎么认为,如果属于业务逻辑,自然设计在domain model内部,就如你举的例子,始终从domain返回状态,至于这个状态是否存在一整套协议对使用domain model的使用者来说是透明的.使用者只需要知道从domain model中获得状态就行了. 想告诉我什么?是支持我的观点还是反对我的观点? 业务逻辑就应该放在Domain Model中实现,不存在尽可能的问题。 薄不薄是最后看起来的效果,不是对设计的要求。 服务层负责协调应用请求到Domain Model的映射,只是工作量不大,所以觉得薄。 |
|
返回顶楼 | |