1.远程外观
为细粒度对象提供粗粒度的外观来改进网络上的效率。
在面向对象模型中,经常有很多规模较小的对象,它们有较小的方法。这样就提供了很多机会来控制和替换某些行为,还可以用良好的命名使应用程序更容易理解。
然而,这种小粒度动作将导致大量对象间的交互,而且这些交互通常需要很多的方法调用。
在一个单一的地址空间内,小粒度的交互工作的很好,但是当你在两个进程之间做调整时这种良好的状态就不存在了。远程调用开销很大,因为有许多事情要做:数据
可能需要编组,可能需要安全检查,发送的数据包需要路由。如果两个进程所处的机器恰巧在地球的两端,那么光速也是一个不能忽略的隐私。进程间的调用开销远比进程
内的开销更大---即使两个进程都在同一个机器上。
那么任何对象可能被作为远程对象使用时,经常需要一个粗粒度的接口来减少完成某些任务所需要的调用次数。这不仅会影响你的方法调用,同样还会影响你的对象。
一个远程外观是一个粗粒度的外观,它建立在大量的细粒度对象之上。所有细粒度对象都没有远程接口,并且远程外观不包括领域逻辑。远程外观要完成的功能是把粗粒度
的方法转换到底层细粒度对象上。
1.运行机制
传统的面向对象方法中,不同的对象有着明确的责任,远程外观解决了这种方法中的分布式问题,并且已经成为解决这种问题的标准模式。细粒度对象非常适合解释复杂
的逻辑,任何复杂的逻辑都可以放大到细粒度对象中。
粒度的大小也是远程外观必须考虑的问题。一些人喜欢非常小的远程外观,他们可能为每一个用例都建立了一个远程外观。我更倾向于粗粒度的结构和较少的远程外观。
对一个中等大小的应用程序来说,只会使用一个远程外观,甚至对于一个大型的应用程序,只会使用6个左右远程外观。这意味着,每一个远程外观都包含了很多方法。
远程外观有有状态和无状态之分。无状态的远程外观可以组成池,这样就可以提高资源利用率。然后,如果交互包括使用会话的状态信息,那么就需要把会话的状态信息
存储在某个地方,可以通过使用客户端会话状态或者数据库会话状态模式来完成,还可以通过实现服务器会话状态来完成。当使用有状态的远程外观的时候,远程外观必须
维持每一个状态,这可以通弄服务器会话状态来很容易的完成,但是这也可能导致性能问题。
除了提供一个粗粒度的接口意外,远程外观还增加了其他几个功能。例如,它的方法中可以提供安全检查。一个访问控制列表可以很明确的告诉你哪个用户可以调用哪个
方法。远程外观也同样提供事物控制。
对于远程外观而言,最大的错误之一就是把领域逻辑放在其中。再三强调,远程外观没有领域逻辑。
1.远程外观和会话外观
远程外观的所有工作都围绕在一个简单的接口上---因此很反对把领域逻辑放入其中。而相对而言,大部分的会话外观的描述都包逻辑放入其中,尤其是工作流这种
类型的逻辑。
2.服务层
它们之间最大的区别在于服务层不需要是远程的,因此并不需要只有粗粒度的方法。为了简化领域模型,你的动作通常终止于粗粒度的方法上,但这是为了使结构
更清晰而不是为了网络效率。而且,服务层并不需要使用数据传输对象,通常,它返回给客户一个真正的领域对象。
如果一个领域模型同时在进程内和远程使用,那么你可以有一个服务层并在这个服务层上分出一个单独的远程外观层。如果进程只是在远程执行,那么这种方法将
会很容易把服务层转成远程外观,并且在服务层中不包含任何远程执行。如果服务层中包含了一些应用逻辑,那么将使远程外观成为一个单独的对象。
2.使用时机
当你需要远程访问细粒度对象模型的时候,你就应该使用远程外观。你可以在保持细粒度对象所带来的好处的同时得到粗粒度接口所带来的种种优点。这种模式最常用的地方
是在表现层和领域模型之间,通常它们处在不同的进程中。在不同机器上的不同进程交互中常常会碰到远程外观,然而在同一机器上的进程间调用的开销也非常大,因此需要一个
粗粒度的接口来为进程间的通信服务,不管进程在哪里。如果所有的访问都在一个单一的进程中,那么就不需要这样的转变。通常你不会看到远程外观使用事务脚本,因为事务
脚本天生就是粗粒度的。
远程外观意味着同步---也就是说,一个远程过程的调用是分布式的。可以基于异步或基于消息的远程通信来大大改善应用的响应速度。
2.数据传输对象
一个为了减少方法调用次数而在进程间传输数据的对象。
当使用远程接口时,例如你正在使用远程外观,每一次调用的代价都非常大。结果是:你需要减少调用次数,这就意味着每一次调用都会传输大量的数据。大量数据传输的方法可以
通过使用大量参数来实现。然后,这对程序来说非常笨拙。
解决办法就是创建一个数据传输对象,这个对象将保留所有调用需要到的数据。它需要被徐丽华以便能在连接中传输。通常,在服务器方使用已给组装器,这个组装器负责在DTO和
任何领域对象之间传输数据。
Sun团体中的许多人使用术语'值对象'来命名这种模式。
1.运行机制
在很多方面,数据传输对象都是我们被告之永远不要使用的对象之一。它经常只不过是一堆域以及它们的getter和setter方法。这种对象的价值在于它们只允许你在一次
调用中传输几部分的信息,这是分布式系统的本质。
无论何时,只要远程对象需要某些数据,它将询问一个合适的数据传输对象。通常,数据传输对象存储的数据量会远远大于远端对象所需要的数据量,但是它应该存储所有
这些数据以备将来之需。由于远程调用的开销,我们宁可每次多传输一些数据避免错误,也不愿意为了某些错误做多次的调用。
数据传输对象通常不仅仅包含一个服务器对象。它从所有的服务器对象中集结所有远程对象可能需要的数据。因此,如果远程对象请求订单对象的数据,那么返回的数据传输
对象中将包含订单数据,用户数,订单项数据。。。
通常不能从领域模型中传输对象。在数据传输对象中的域都是非常简单和原始的,比如像字符串和日期这样的简单类。数据传输对象中保存那么多简单的属性是为了序列化它们,
并且可以使传输的双方更容易理解。
有一点很清楚,那就是数据传输对象的设计都是围绕特定的客户端来进行的。
一个要考虑的问题是,是用单一数据传输对象来处理整个交互,还是用不同数据传输对象来处理不同请求。用不同的数据传输对象使得我们很容易看清楚再每次调用中传输了什么
数据,但是这样会产生大量的数据传输对象。单一数据传输对象会减少编码工作,但是会使得我们很难掌握每次调用所需传输的数据。
对于数据传输对象,一个最常见的问题是,你是使用文本序列化格式还是二进制序列化格式。
2.使用时机
当你需要在一个方法调用中在两个进程之间传输多个数据项时,应该使用数据传输对象格式。