po什么意思 po什么意思( 三 )


对于DTO和DO的命名规则 , 请参见:
https://www.cnblogs.com/qixuejia/p/10789612.html
DTO与DO的应用从上一节的例子中 , 细心的读者可能会发现问题:既然getUser *** 返回的UserInfo不应该包含password , 那么就不应该存在password这个属性定义
但如果同时有一个createUser的 ***  , 传入的UserInfo需要包含用户的password , 怎么办?
在设计层面 , 展示层向服务层传递的DTO与服务层返回给展示层的DTO在概念上是不同的 , 但在实现层面 , 我们通常很少会这样做(定义两个UserInfo , 甚至更多) , 因为这样做并不见得很明智
我们完全可以设计一个完全兼容的DTO , 在服务层接收数据的时候 , 不该由展示层设置的属性(如订单的总价应该由其单价、数量、折扣等决定) , 无论展示层是否设置 , 服务层都一概忽略 , 而在服务层返回数据时 , 不该返回的数据(如用户密码) , 就不设置对应的属性 。
对于DO来说 , 还有一点需要说明:为什么不在服务层中直接返回DO呢?这样可以省去DTO的编码和转换工作 , 原因如下:

  • 两者在本质上的区别可能导致彼此并不一一对应 , 一个DTO可能对应多个DO , 反之亦然 , 甚至两者存在多对多的关系 。
  • DO具有一些不应该让展示层知道的数据
  • DO具有业务 ***  , 如果直接把DO传递给展示层 , 展示层的代码就可以绕过服务层直接调用它不应该访问的操作 , 对于基于AOP拦截服务层来进行访问控制的机制来说 , 这问题尤为突出 , 而在展示层调用DO的业务 *** 也会因为事务的问题 , 让事务难以控制 。
  • 对于某些ORM框架(如Hibernate)来说 , 通常会使用“延迟加载”技术 , 如果直接把DO暴露给展示层 , 对于大部分情况 , 展示层不在事务范围之内(Open session in view在大部分情况下不是一种值得推崇的设计) , 如果其尝试在Session关闭的情况下获取一个未加载的关联对象 , 会出现运行时异常(对于Hibernate来说 , 就是LazyInitiliaztionException)
  • 从设计层面来说 , 展示层依赖于服务层 , 服务层依赖于领域层 , 如果把DO暴露出去 , 就会导致展示层直接依赖于领域层 , 这虽然依然是单向依赖 , 但这种跨层依赖会导致不必要的耦合 。
对于DTO来说 , 也有一点必须进行说明 , 就是DTO应该是一个“扁平的二维对象”
举个例子来说明:如果User会关联若干个其他实体(例如Address、Account、Region等) , 那么getUser()返回的UserInfo , 是否就需要把其关联的对象的DTO都一并返回呢?
如果这样的话 , 必然导致数据传输量的大增 , 对于分布式应用来说 , 由于涉及数据在网络上的传输、序列化和反序列化 , 这种设计更不可接受 。
如果getUser除了要返回User的基本信息外 , 还需要返回一个AccountId、AccountName、RegionId、RegionName , 那么 , 请把这些属性定义到UserInfo中 , 把一个“立体”的对象树“压扁”成一个“扁平的二维对象”
笔者目前参与的项目是一个分布式系统 , 该系统不管三七二十一 , 把一个对象的所有关联对象都转换为相同结构的DTO对象树并返回 , 导致性能非常的慢 。

推荐阅读