12.1 模式简介
- 在公司里,许多人都在工作着。有接待人员、销售人员、生产产品的工人、管理人员,还有负责发货和搬运产品的人……正是这些各个岗位上的人们互相协作,公司才能正常运营。如果将公司看作一个整体,它就是一个具有人格的组织——法人。
- Active是 “主动的” 的意思,因此 Active Object 就是“主动对象”的意思。所谓 “主动的”,一般指 “有自己特有的线程”。因此,举例来说,Java 的 java.lang.Thread 类的实例就是一种主动对象。
- 不过,在Active Object模式中出场的主动对象可不仅仅 “有自己特有的线程”。它同时还具有可以从外部接收和处理异步消息并根据需要返回处理结果的特征。
- Active Object模式中的主动对象会通过自己特有的线程在合适的时机处理从外部接收到的异步消息。
12.3 ActiveObject模式中的角色
12.3.1 Client(委托者)
- Client角色调用 ActiveObject 角色的方法来委托处理,它能够调用的只有 ActiveObject 角色提供的方法。调用这些方法后,(如果ActivationQueue角色没有满)程序控制权会立即返回。
- 虽然Client角色只知道ActiveObject角色,但它实际调用的是Proxy角色。
- Client角色在获取处理结果时,会调用 VirtualResult 角色的 getResultvalue 方法。这里使用了Future模式。
12.3.2 ActiveObject(主动对象)
- ActiveObject 角色定义了主动对象向 Client 角色提供的接口(API)。
12.3.3 Proxy(代理人)
- Proxy角色负责将方法调用转换为 MethodRequest 角色的对象。转换后的MethodRequest角色会被传递给 Scheduler 角色。
- Proxy角色实现了ActiveObject角色提供的接口(API)。
- 调用 Proxy 角色的方法的是 Client 角色。将方法调用转换为MethodRequest角色,并传递给Scheduler角色的操作都是使用Client角色的线程进行的。
12.3.4 Scheduler
- Scheduler角色负责将 Proxy 角色传递来的 MethodRequest 角色传递给 ActivationQueue 角色,以及从 ActivationQueue 角色取出并执行 MethodRequest 角色这两项工作。
- Client角色的线程负责将MethodRequest角色传递给ActivationQueue角色。
- 而从ActivationQueue角色取出并执行MethodRequest角色这项工作则是使用Scheduler角色自己的线程进行的。在ActiveObject模式中,只有使用Client角色和Scheduler角色时才会启动新线程。
- Scheduler角色会把MethodRequest角色放入ActivationQueue角色或者从ActivationQueue角色取出MethodRequest角色。
12.3.5 MethodRequest
- MethodRequest角色是与来自Client角色的请求对应的角色。MethodRequest定义了负责执行处理的Servant角色,以及负责设置返回值的Future角色和负责执行请求的方法(execute)
- MethodRequest角色为主动对象的接口(API)赋予了对象的表象形式。
12.3.6 ConcreteMethodRequest
- ConcreteMethodRequest角色是使MethodRequest角色与具体的方法相对应的角色。对于ActiveObject角色中定义的每个方法,会有各个类与之对应。
- 各个 ConcreteMethodRequest 角色中的字段分别与方法的参数相对应。
12.3.7 Servant(仆人)
- Servant角色负责实际地处理请求。
- 调用Servant角色的是Scheduler角色的线程。Scheduler角色会从ActivationQueue角色取出一个MethodRequest角色(实际上是ConcreteMethodRequest角色)并执行它。此时,Scheduler角色调用的就是 Servant 角色的方法。
- Servant 角色实现了ActiveObject角色定义的接口(API)。
- Proxy角色会将请求转换为MethodRequest角色,而Servant角色则会实际地执行该请求。
- Scheduler角色介于Proxy角色和Servant角色之间,负责管理按照什么顺序执行请求。
12.3.8 ActivationQueue(主动队列)
- ActivationQueue角色是保存MethodRequest角色的类。
- 调用 putRequest 方法的是Client角色的线程,而调用 takeRequest 方法的是Scheduler角色的线程。这里使用了 Producer-Consumer 模式。
12.3.9 VirtualResult(虚拟结果)
- VirtualResult角色与Future角色、RealResult角色共同构成了Future模式。
- Client角色在获取处理结果时会调用VirtualResult角色(实际上是Future角色)的getResultValue方法。
12.3.10 Future(期货)
- Future角色是Client角色在获取处理结果时实际调用的角色。当处理结果还没有出来的时候,它会使用 Guarded Suspension 模式让Client角色的线程等待结果出来。
12.3.11 RealResult(真实结果)
- RealResult角色是表示处理结果的角色。
- Servant角色会创建一个 RealResult 角色作为处理结果,然后调用 Future 角色的 setRealResult 方法将其设置到 Future 角色中。
12.4 拓展思路的要点
12.4.1 到底做了些什么事情
- 模式的左侧有Client角色,右侧有activeobject包中的各个登场角色。Client角色会调用ActiveObject角色的方法,然后根据需要使用Future模式获取返回值。
- 与通常的实现方式不同的是,这里的 “方法” 并不是由Client角色的线程执行的。也就是说,通过Active Object模式,我们实现了 “异步方法”,也可以说是实现了“异步消息”。
- 下面我们再来看看activeobject包中的内容。这里,activeobject包中的所有登场角色互相协作,组成了一个主动对象,这个主动对象具有以下特征:
- 定义了接口(API):由 ActiveObject 角色定义API
- 接收异步消息:Proxy角色将方法调用转换为 MethodRequest 角色后保存在 ActivationQueue 角色中
- 与Client角色运行于不同的线程:由 Scheduler 角色提供线程
- 执行处理:由 Servant 角色单线程执行处理
- 返回返回值:Future角色是返回值的提货单
12.4.2 增加方法
- 想要增加方法,我们可以按照以下步骤进行修改:
- 在 Activeobject 接口中增加方法
- 新编写一个与该方法对应的类——MethodRequest的子类
- 在 Proxy 类中增加方法
- 在 Servant 类中增加方法
- 如果方法需要返回值,那么就使用 Future 模式。创建 Future 角色是 Proxy 类的工作,而创建 RealResult 角色则是 Servant 类的工作。
- 这里不需要修改 SchedulerThread 类。因为 SchedulerThread 类并不知道 “主动对象”的方法,它只是调用MethodRequest 角色的 execute 方法而已。