论坛首页 Java企业应用论坛

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

浏览 25357 次
精华帖 (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层来完成更合理,因为它可以共享多种应用实现相同的部分.
0 请登录后投票
   发表时间:2005-03-16  
to partech :
直接传递po(domain object)到view是domain driven design的一种思想,在Transaction Script范畴下探讨它的合理性是没有任何意义的。

如果你想继续讨论,你可以试着在用domain driven design(先设计domain model,在定义业务接口)建模的条件下阐述你的观点。
0 请登录后投票
   发表时间: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吗?
0 请登录后投票
   发表时间: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到应用层了?
别蒙我啊,老兄!
0 请登录后投票
   发表时间:2005-03-16  
引用
domain driven design是先设计Domain Model再定义业务接口的意思吗?

这也是oo建模的思想啊:先设计domain model,domain model应该厚,有一个业务需求就封装一个薄的service接口给客户端调用,这样可以高效的复用domain model中的逻辑。
引用
谁说domain driven design就一定要传递PO到应用层了?

不是一定,是这样做最优雅。
0 请登录后投票
   发表时间: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确实是可以复用的,特别当你在把他们统一考虑的时候。
0 请登录后投票
   发表时间: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的具体结构呢,前台的状态控制就让我够恼火的了。呵呵
0 请登录后投票
   发表时间: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的重要区别,建议另开话题,我想会有许多人感兴趣的讨论的。
0 请登录后投票
   发表时间: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中获得状态就行了.
0 请登录后投票
   发表时间:2005-03-17  
youcai 写道

Service层的设计应该尽可能的薄,业务逻辑则尽可能的由domain model完成,这样关于前台需要的属性,就看你的设计怎么认为,如果属于业务逻辑,自然设计在domain model内部,就如你举的例子,始终从domain返回状态,至于这个状态是否存在一整套协议对使用domain model的使用者来说是透明的.使用者只需要知道从domain model中获得状态就行了.

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

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