论坛首页 Java企业应用论坛

炒PO-VO-DTO的冷饭,Remote下PO的运用方式问题

浏览 25356 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2005-03-17  
partech 写道

想告诉我什么?是支持我的观点还是反对我的观点?
业务逻辑就应该放在Domain Model中实现,不存在尽可能的问题
薄不薄是最后看起来的效果,不是对设计的要求。
服务层负责协调应用请求到Domain Model的映射,只是工作量不大,所以觉得薄。


partech 写道

嗯,如果你所写的方法是在Customer中,那么恭喜你,你会后很多机会来重构Customer,因为客户签订的协议会与日俱增。
Customer是很底层的业务对象,不要老是去变动它!

这个变动是谁导致的,属于业务变动吗?

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意味着客户端也需要做相应的变更。

为什么不能放在Customer中了?
0 请登录后投票
   发表时间:2005-03-17  
To All
我没有实际使用过DTO和ViewObject, 不是很清楚比较好的实践做法是如何, 在此想请教一下大家:

有这样的模型: 一个人(Person)属于某个公司(Company), 这个人有联系地址(Address)
那么如果我传递给Remote Client显示的话, 是否需要根据显示内容的不同, 而构建多种View Object?

比如显示Person的名字和他所在公司的名字, 那么就要构建一个PersonCompanyViewObject:
然后在client调用: PersonCompanyViewObject.personName, PersonCompanyViewObject.companyName

如果还需要显示Person的名字和他的联系地址, 那么还得另外构建一个PersonAddressViewObject:
在client调用: PersonAddressViewObject.personName, PersonAddressViewObject.addressZipCode

假如我能够把Person这个对象直接传递到client的话, 我可以利用对象关系, 直接写:
Person.name, Person.company.name
和Person.name, Person.address.zipCode

不知道我理解得是否正确?


To jackyz
我觉得透明的分布式lazy load是可行的, 考虑利用net.sf.hibernate.Interceptor的onLoad方法, 对于每个被Hibernate load的对象加上代理(可以用CGLIB),代理它所有getLazyCollection类型的方法, 让这个proxy remote invoke server的某个指定方法:
session.refresh(proxy, LockMode.NONE);;
Hibernate.initialize(proxy.getLazyCollection(););;


这样对于客户端就是透明的了, 你怎样看待这种做法?
0 请登录后投票
   发表时间:2005-03-17  
pufan 写道
domain model即不属于后台也不属于前台,domain model的设计是在各层划分前实现的,也就是说当domain model的接口确定下来l时系统的层次尚未划分(可能是bs,可能cs,可能是三层也可能是n层),domain model 是在各层之上的,应该贯穿于各层之间。


我的想法就是这样的,各个层次上的DomainObject都是一样的,可能他们在各层的具体实现并不一样.但接口一样就行.

partech 写道
Service层负责实现Service层的接口,它当然要输出VO(Value Ojbect -- 不知道你的ViewObject是什么东东?)给应用层用。


Service层负责实现Service层的接口,但它的输出格式为什么就天经地义的必须是VO(Value Ojbect)呢?
如果传输方面代价不高,应用层为什么不可以得到一个DomainObject来用呢?或者说,传过来的VO为什么不能包装(适配)成为一个DomainObject来供应用层使用呢?----这么做显而易见的好处就是屏蔽了VO带来的限制.

当然,要满足这样的条件,VO显然已经不能是之前提到的"经过特定裁减的扁平的传输对象".

关于ViewObject请看前面这一句:

jackyz 写道
DTO中所传递的东西其实就是显示中要用到的数据,我认为它就是ViewObject(实际上ViewObject也受限于DTO所定义的方法).比较两者,区别在于DTO是将DomainObject->ViewObject的Mapping放在Service端,而非DTO将这个过程放在Client端.


或者说,ViewObject是view层Model的"数据部分".

partech 写道
Service层对应用层的功能不可知,那它是为谁服务呢?如果你说的是特定的应用层,那么确实Service层对它一无所知。Service层对可能的所有应用提供统一的服务接口。


partech 写道
Web客户端和Rich客户端我认为某些VO确实是可以复用的,特别当你在把他们统一考虑的时候。


我说的就是"特定的应用层","Service层对可能的所有应用提供统一的服务接口".在这一点上,我们的看法相同.但我认为,比较理想的情况是"所传递的对象"到了应用层能被"还原(或者模拟)"出一个实现DomainObject接口的对象.那么,在"对于所有的应用提供统一的服务接口"这个目标上,要做得更彻底一些.

即使这里在传输上的确是存在着一个DTO层,但我们也可以将它作为一个实现来隐藏,对调用者(应用层代码)屏蔽它的存在,而在客户端提供一个使用统一DomainObject接口的实现.
0 请登录后投票
   发表时间:2005-03-17  
youcai 写道
partech 写道

想告诉我什么?是支持我的观点还是反对我的观点?
业务逻辑就应该放在Domain Model中实现,不存在尽可能的问题
薄不薄是最后看起来的效果,不是对设计的要求。
服务层负责协调应用请求到Domain Model的映射,只是工作量不大,所以觉得薄。


partech 写道

嗯,如果你所写的方法是在Customer中,那么恭喜你,你会后很多机会来重构Customer,因为客户签订的协议会与日俱增。
Customer是很底层的业务对象,不要老是去变动它!

这个变动是谁导致的,属于业务变动吗?

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意味着客户端也需要做相应的变更。

为什么不能放在Customer中了?

java代码:


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;
    }
  }
  ...
}
0 请登录后投票
   发表时间:2005-03-17  
Quake Wang 写道
To All
我没有实际使用过DTO和ViewObject, 不是很清楚比较好的实践做法是如何, 在此想请教一下大家:

有这样的模型: 一个人(Person)属于某个公司(Company), 这个人有联系地址(Address)
那么如果我传递给Remote Client显示的话, 是否需要根据显示内容的不同, 而构建多种View Object?

比如显示Person的名字和他所在公司的名字, 那么就要构建一个PersonCompanyViewObject:
然后在client调用: PersonCompanyViewObject.personName, PersonCompanyViewObject.companyName

如果还需要显示Person的名字和他的联系地址, 那么还得另外构建一个PersonAddressViewObject:
在client调用: PersonAddressViewObject.personName, PersonAddressViewObject.addressZipCode

假如我能够把Person这个对象直接传递到client的话, 我可以利用对象关系, 直接写:
Person.name, Person.company.name
和Person.name, Person.address.zipCode

不知道我理解得是否正确?

基本上是这样的,但是ValueObject的名称不是那样的,因为你写的这些名称。
隐含的意味着Client知道Domain Model的结构。
之所以会有不同的ValueObject的需要,那一定是在业务上的目的不同。
最好根据不同的目的来命名ValueObject,比如PersonInCompanyInfo。
PersonPrivateInfo等等。
对于前台开发人员来说它确实是不同的概念。对于用户来说也是这样的。
从客户和前台的观点来看,它们是交互的输入输出对象。而不是复杂的DomainObject结构。
3 请登录后投票
   发表时间:2005-03-17  
Quake Wang 写道
To All
我没有实际使用过DTO和ViewObject, 不是很清楚比较好的实践做法是如何, 在此想请教一下大家:

有这样的模型: 一个人(Person)属于某个公司(Company), 这个人有联系地址(Address)
那么如果我传递给Remote Client显示的话, 是否需要根据显示内容的不同, 而构建多种View Object?

比如显示Person的名字和他所在公司的名字, 那么就要构建一个PersonCompanyViewObject:
然后在client调用: PersonCompanyViewObject.personName, PersonCompanyViewObject.companyName

如果还需要显示Person的名字和他的联系地址, 那么还得另外构建一个PersonAddressViewObject:
在client调用: PersonAddressViewObject.personName, PersonAddressViewObject.addressZipCode

假如我能够把Person这个对象直接传递到client的话, 我可以利用对象关系, 直接写:
Person.name, Person.company.name
和Person.name, Person.address.zipCode

不知道我理解得是否正确?


To jackyz
我觉得透明的分布式lazy load是可行的, 考虑利用net.sf.hibernate.Interceptor的onLoad方法, 对于每个被Hibernate load的对象加上代理(可以用CGLIB),代理它所有getLazyCollection类型的方法, 让这个proxy remote invoke server的某个指定方法:
session.refresh(proxy, LockMode.NONE);;
Hibernate.initialize(proxy.getLazyCollection(););;


这样对于客户端就是透明的了, 你怎样看待这种做法?


我们的看法一致.

我想尽量避免的就是前面的做法而采用后面的"利用对象关系"的方式.

那么,最适合的DTO粒度就是Hibernate没有LazyLoad之前的内部对象.

这样的话,问题就变成如何在PO上加入透明的RPC机制了.
0 请登录后投票
   发表时间:2005-03-17  
to partech,
如果Customer对象无论如何都不应当知道直接签订了多少的协议。那么客户状态会和谁有关?
只要明确这个状态就是Customer的,那么Customer.getStatus();是最自然不过的表达.至于具体的实现如何获得状态,那就跟据实际情况做吗.
0 请登录后投票
   发表时间:2005-03-17  
jackyz 写道
Service层负责实现Service层的接口,但它的输出格式为什么就天经地义的必须是VO(Value Ojbect)呢?
如果传输方面代价不高,应用层为什么不可以得到一个DomainObject来用呢?或者说,传过来的VO为什么不能包装(适配)成为一个DomainObject来供应用层使用呢?----这么做显而易见的好处就是屏蔽了VO带来的限制.

那么请问你在什么时候才能定义出这服务接口呢?
如果按照你的设计,必须要等到DomainObject都稳定后,该接口才能定义出来。
但是你的DomainObject的设计又依赖于它使用的情况(也就是服务接口提供的功能),这样你的DomainObject同服务接口就双向依赖了,你会先处理哪一个呢?你如何处理这种问题?
或者,你会采用交替的方式开发两者,那么你就会频繁的重构接口,因为你会不断地
重构DomainObject。
3 请登录后投票
   发表时间:2005-03-17  
Quake Wang 写道

假如我能够把Person这个对象直接传递到client的话, 我可以利用对象关系, 直接写:
Person.name, Person.company.name
和Person.name, Person.address.zipCode

不知道我理解得是否正确?

同意这种,对于数据结构近似的地方尽量采用一个dto,真有特殊的时候,再考虑增加新的dto.结果会类似于domain model,但应更简单和直接.
这里没有明确的标准,需要自己把握.
0 请登录后投票
   发表时间:2005-03-17  
youcai 写道
to partech,
如果Customer对象无论如何都不应当知道直接签订了多少的协议。那么客户状态会和谁有关?
只要明确这个状态就是Customer的,那么Customer.getStatus();是最自然不过的表达.至于具体的实现如何获得状态,那就跟据实际情况做吗.

是的是和客户相关,但是Customer对象确实是不知道任何一个协议的,协议自己
知道自己属于那个客户。在这里强制了一个关联方向即协议 ---〉客户。
现实中的关联都是双向的,但在程序里我们可以将它实现为单向的。
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics