Role Object(角色对象)模式

Dirk Bäumer等 著,透明 译
意图
通过向组件对象加入对用户透明的角色对象(role object)——每个角色对象扮演了组件对象需要在一个用户的环境(context)中扮演的角色——使组件对象能适应不同用户的需要。每个“用户的环境”可能是它自己的一个应用程序,通过使用这个模式,应用程序与其它应用程序的耦合度将得到降低。
动机
一个面向对象系统总是以一系列特征性的基本抽象(key abstract)为基础的。每个基本抽象都由一个相应的类根据其抽象状态和行为模拟实现。在设计小规模的应用程序时,这个机制通常运行得很好。但是,当我们要把系统的规模扩大成一套完整的应用程序时,我们就必须面对各种不同的客户,这些客户希望根据我们的基本抽象得到各自不同的、根据环境指定的视图(view)。
假设我们正在为银行的投资部门开发一个支持软件,我们的基本抽象之一是表示“投资者”的概念。
因此,我们的设计模型中应该有一个Customer类,这个类的接口提供了管理消费者的姓名、住址、储蓄、存款余额等属性的操作。
现在,假设这个银行的贷款部门也需要软件支持。看起来,我们的设计不能满足处理一个贷款者客户的需要。很明显,我们必须为Customer类增加更多的状态和操作,使之能管理客户的贷款额、信用级别、债券等信息。
把几个根据不同环境指定的视图包含在同一个类中,这样的做法最可能的后果是把基本抽象变成一个臃肿的接口。对这样一个臃肿的接口的理解和维护都是非常困难的。当一个未知的变化发生时,你无法温和的处理它,而通常只能任它引发对一系列程序模块的重新编译(recompilation)。而对用户指定的接口部分的变化则很可能影响到其他的子系统或应用程序。
这里有一个简单的解决方案:扩展Customer类,加入Borrower和Investor两个新的子类,让它们分别捕
获贷款者和投资者各自特殊的事件。从对象身份的角度来考虑,子类化就意味着分属两个不同子类的对象是不同的。因此,一个既是投资者又是贷款者的客户就要扮演有截然不同的身份的两个对象。对象的“身份”只能以附加的机制来模拟(例如C++的运行时类型识别RTTI),如果两个对象有同样身份,它们必定有恒定不变且互不相同的继承属性。无论如何,假设要构造系统中所有客户的列表,我们将不可避免的陷
入多态搜索(polymorphic search)的麻烦。除非我们很小心的避免复制(duplicate)对象,否则同一个客户对象将作为不同的角色重复出现。
角色对象模式模拟了根据环境指定的对象视图,各个单独的角色对象被核心对象(core object)动态添加、移除。最终得到的对象聚合体作为一个逻辑对象进行它自己的行为。

象Customer这样的基本抽象被定义成一个抽象超类。它只提供一个接口,不做任何实现。Customer类指定了处理客户住址、存款余额这样的操作,并且定义了一个管理角色的最小化协议。子类CustomerCore
实现了Customer的接口。
CustomerRole则提供了用户指定角色的超类,并且它也支持Customer的接口。CustomerRole是一个抽象类,它不能被实例化。CustomerRole的具体子类——例如Borrower或者Investor——定义并实现了用户指定角色对象的接口,只有这些子类才能在运行时被实例化。Borrower类定义了贷款部门需要的客户对象视图,它定义了一些附加操作以管理客户的信用和债券等信息。同样,Investor类也添加了投资部门指定的客户视图需要的操作。
象“贷款应用程序”这样的一个用户可能通过Customer的接口使用CustomerCore类,也可能使用某个具体CustomerRole子类的一个对象。假想这样的情况:贷款应用程序通过某个Customer实例的Customer接口了解到它,并且应用程序可能想检查这个Customer是否扮演着贷款者的角色。于是应用程序调用该对象的hasRole()方法,这个方法会告诉调用者该对象的角色。在本例中,我们假设我们的每个角色都有一个简单string类型的名字。如果这个Customer对象可以扮演名叫“Borrower”的角色,贷款应用程序会要求它传递一个自己的引用给相关的对象,然后应用程序就可以使用这个引用调用贷款者专用的操作了。

与此相似,“投资者”角色被它自己的应用程序处理。如果这两个应用程序不需要互相了解,那么角
色对象的使用就可以帮助它们解耦。贷款应用程序不需要加载投资者角色,同时投资应用程序也不需要加载贷款者角色。
适用性
在以下情况下可以使用Role Object模式:
􀁺􀀃 你希望在不同的环境中处理同一个基本抽象(每个环境可能是一个独立的应用程序),并且你不希望把所得到的环境相关的接口放到同一个类接口中去。
􀁺􀀃 你希望能动态决定处理何种有用的对象,希望角色能根据要求在运行时被添加或移除,而不是在编译时被静态绑定。
􀁺􀀃 你希望在不同的环境中保持逻辑对象的一致性。
􀁺􀀃 你希望让角色/用户(role/client)互不依赖,这样对角色的修改不会影响到与之无关的用户。
如果有如下情况,不要使用这个模式:
􀁺􀀃 你的潜在角色有很强的相互依赖。有其他的一些使用“角色”的方法,Fowler给出了使用这些方法的向导,并指出应该在什么时候使用什么模式[Fowler97]。
结构
下面是Role Object模式的结构图。

  • 25
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值