知识卡片
远程外观与数据传输对象的配套使用
内容
既然分布不可避免,好的做法是把”细粒度”和”粗粒度”这两种设计各自限制在自己该待的地方:进程内部照样可以自由使用细粒度对象,关键是只让它们停留在进程内部;而在分布边界上专门放一层粗粒度对象,这层对象自己不做任何实际业务工作,唯一职责是把内部细粒度对象包装成一个远程可访问的外观——这就是远程外观。这样做的好处是让”付出粗粒度接口的代价”这件事变得显式化:只有真正需要被远程调用的对象才套上这层外观,开发者能清楚看到自己在哪里、为什么要付出这个代价,避免”透明”掩盖了远程调用本该被认真对待的事实;同时使用者只要清楚自己是在同一进程内运行,仍然可以直接用底层的细粒度对象,分布策略因此变得非常显性和可控。远程外观通常要搭配数据传输对象一起使用——因为跨越分布边界传输的不只是粗粒度的方法调用,还需要把结果打包成一整块数据一起送过去:领域对象本身通常不能直接通过网络发送,因为它们内部靠一张细粒度的本地对象引用网络互相勾连,不适合被拆解序列化,因此要把客户端真正需要的所有数据单独打包进一个专门用于传输的对象——这就是数据传输对象(不少企业Java开发者习惯称之为”值对象”,容易和本书别处讲的值对象混淆,需要留意区分)。使用数据传输对象有一条重要约束:它只应该引用其他数据传输对象和字符串这类原始类型,绝不能引用网络对端访问不到的东西,否则序列化传输就会失败或产生悬空引用。
结构图:
flowchart LR
C["客户端(另一进程)"] -->|"粗粒度调用"| F["远程外观<br/>不含业务逻辑,纯粹外观"]
F --> D["细粒度领域对象<br/>只在本进程内使用"]
F -->|"打包结果"| T["数据传输对象<br/>只含原始类型/其他DTO引用"]
T --> C
参考来源
- 位置:《企业应用架构模式》第一部分"表述"之"第7章 分布策略"之"7.4 关于分布边界"(源文件:_epub-src/OEBPS/Text/000048.html)
- 结论依据:原文说明"关键要记住只在进程内部使用它们,而在分布边界上放置粗粒度的对象,它们唯一的目的是去提供一个到细粒度对象的远程接口……因此称为远程外观……应该将客户端需要的所有数据打包在一个特定对象中以便于传输——就成了所谓的数据传输对象……一个数据传输对象一般只引用其他的数据传输对象和一些如字符串等原始类型的对象",直接支撑本卡结构图。
- 原始内容:使用远程外观能减少粗粒度接口引入的困难。这样,只有那些真正需要远程服务的对象才使用粗粒度接口,这也使开发人员清楚所付出的代价。