类—职责—协作者建模( 二 )


5.适合时 , 职责应由相关类共享 。 很多情况下 , 各种相关对象必须在同一时间展示同样的行为 。 例如 , 考虑一个视频游戏 , 必须显示如下类:Player、PlayerBody .PlayerArms、PlayerLegs和PlayerHead 。 每个类都有各自的属性(例如position .orientation、color和speed) , 并且所有属性都必须在用户操纵游戏杆时进行更新和显示 。 因此 , 每个对象必须共享职责update和 display 。 Player知道在什么时候发生了某些变化并且需要update操作 。 它和其他对象协作获得新的位置或方向 , 但是每个对象控制各自的显示 。
协作 。 类用一种或两种方法来实现其职责:(1)类可以使用其自身的操作控制各自的属性 , 从而实现特定的职责;(2)类可以和其他类协作 。 有人这样定义协作:
协作是以客户职责实现的角度表现从客户到服务器的请求 。 协作是客户和服务器之间契约的具体实现……如果为了实现某个职责需要发送任何消息给另一个对象 , 我们就说这个对象和其他对象有协作 。 单独的协作是单向流 , 即表示从客户到服务器的请求 。 从客户的角度看 , 每个协作都和服务器的某个特定职责实现相关 。
要识别协作可以通过确认类本身是否能够实现自身的每个职责 。 如果不能实现每个职责 , 那么需要和其他类交互 , 因此就要有协作 。
例如 , 考虑SafeHome的安全功能 。 作为活动流程的一部分 , ControlPanel对象必须确定是否启动所有的传感器 , 定义名为determine-sensor-status()的职责 。 如果传感器是开启的 , 那么ControlPanel必须设置属性 status为“未准备好” 。 传感器信息可以从每个Sensor对象获取 , 因此只有当ControlPanel和Sensor协作时才能实现determine-sensor-status()职责 。
为帮助识别协作者 , 分析师可以检查类之间三种不同的通用关系:( 1) is-part-of(是……一部分)关系;( 2) has-knowledge-of(有……的知识)关系;( 3 ) depends-upon(依赖…)关系 。 在下面的文字中将简单地分别说明这三种通用关系 。
属于某个聚合类一部分的所有类可通过is-part-of关系和聚合类连接 。 考虑前面提到的视频游戏中所定义的类 , PlayerBody是Player的一部分 , PlayerArms、PlayerLegs和PlayerHead也类似 。 在UML中 , 使用如图所示的聚合方式表示这些关系 。
类—职责—协作者建模文章插图
复合聚合类
当一个类必须从另一个类中获取信息时 , 就建立了has-knowledge-of关系 。 前面所说的determine-sensor-status()职责就是has-knowledge-of关系的一个例子 。
depends-upon关系意味着两个类之间具有has-knowledge-of和is-part-of不能实现的依赖关系 。 例如 , PlayerHead通常必须连接到PlayerBody(除非视频游戏特别暴烈) , 然而每个对象并没有其他对象的直接信息 。 PlayerHead对象的center-position属性由PlayerBody的中心位置确定 , 该信息通过第三方对象Player获得 , 即 PlayerBody需要 Player 。 因此 , PlayerHead依赖PlayerBody 。
在所有情况下 , 我们都把协作类的名称记录在CRC模型索引卡上 , 紧靠在协作的职责旁边 。 因此 , 索引卡包含一个职责列表以及相关的能够实现这些职责的协作 。
当开发出一个完整的CRC模型时 , 利益相关者可以使用如下方法评审模型 。
1.所有参加(CRC模型)评审的人员拿到一部分CRC模型索引卡 。 拆分协作卡片(也就是说每个评审员不得有两张存在协作关系的卡片) 。
2.分类管理所有的用例场景(以及相关的用例图) 。
3.评审组长细致地阅读用例 。 当评审组长看到一个已命名的对象时 , 给拥有相应类索引卡的人员一个令牌 。 例如 , SafeHome的一个用例包含如下描述:
房主观察SafeHome控制面板以确定系统是否已经准备接收输入 。 如果系统没有准备好 , 房主必须手工关闭窗户(门)以便指示器呈现就绪状态 。 (未就绪指示器意味着某个传感器是开启的 , 也就是说某个门或窗户是打开的 。 )


推荐阅读