类—职责—协作者建模

类–职责-协作者(Class-Responsibility-Collaborator , CRC)建模提供了一个简单方法 , 可以识别和组织与系统或产品需求相关的类 。 Ambler用如下文字解释了CRC建模:
CRC模型实际上是表示类的标准索引卡片的集合 。 这些卡片分三部分 , 顶部写类名 , 卡片主体左侧部分列出类的职责 , 右侧部分列出类的协作者 。
事实上 , CRC模型可以使用真实的或虚拟的索引卡 , 意图是有组织地表示类 。 职责是和类相关的属性和操作 。 简单地说 , 职责就是“类所知道或能做的任何事” 。 协作者是提供完成某个职责所需要信息的类 。 通常 , 协作意味着信息请求或某个动作请求 。
FloorPlan类的一个简单CRC 索引卡如图所示 。 CRC 卡上所列出的职责只是初步的 , 可以添加或修改 。 在职责栏右边的Wall和Camera是需要协作的类 。
类—职责—协作者建模文章插图
CRC模型索引卡
类 。 类的分类可以通过如下分类方式进行扩展:
实体类 , 也称作模型或业务类 , 是从问题说明中直接提取出来的(例如FloorPlan和 Sensor) 。 这些类一般代表保存在数据库中和贯穿在应用程序中(除非被明确删除)的事物 。
边界类用于创建用户可见的和在使用软件时交互的接口(如交互屏幕或打印的报表) 。 实体类包含对用户来说很重要的信息 , 但是并不显示这些信息 。 边界类的职责是管理实体对象呈现给用户的方
式 。 例如 , Camera Window的边界类负责显示SafeHome系统监视摄像机的输出 。
控制类自始至终管理“工作单元” 。 也就是说 , 控制类可以管理:(1)实体类的创建或更新;(2)边界类从实体对象获取信息后的实例化;(3)对象集合间的复杂通信;(4)对象间或用户和应用系统
间交换数据的确认 。 通常 , 直到设计开始时才开始考虑控制类 。
职责 。 我们在给类分配职责时可以根据以下指导原则:
1.智能系统应分布在所有类中以求最大程度地满足问题的需求 。 每个应用系统都包含一定程度的智能 , 也就是系统所知道的以及所能完成的 。 智能在类中可以有多种分布方式 。 建模时可以把“不灵巧”(Dumb)类(几乎没有职责的类)作为一些“灵巧”类(有很多职责的类)的从属 。 尽管该方法使得系统中的控制流简单易懂 , 但同时有如下缺点:把所有的智能集中在少数类 , 使得变更更为困难;将会需要更多的类 , 因此需要更多的开发工作 。
如果智能系统更平均地分布在应用系统的所有类中 , 每个对象只了解和执行某些事情(通常是适度集中) , 并提高系统的内聚性 , 这将提高软件的可维护性并减少变更的副作用 。
为了确定分布智能系统是否恰当 , 应该评估每个CRC模型索引卡上标记的职责 , 以确定某个类是否应该具有超长的职责列表 。 如果有这种情况就表明智能太集中 。 此外 , 每个类的职责应表现在同一抽象层上 。 例如在聚合类CheckingAccount操作列表中 , 评审人员注意到两项职责:账户余额和已结算的支票 。 第一个操作的职责意味着复杂的算术和逻辑过程 , 第二个操作的职责是指简单的办事员活动 。 既然这两个操作不是相同的抽象级别 , 因此已结算的支票应该被放在CheckEntry的职责中 , 这是由聚合类CheckingAccount压缩得到的一个类 。
2.每个职责的说明应尽可能具有普遍性 。 这条指导原则意味着应在类的层级结构的上层保持职责(属性和操作)的通用性(因为它们更有一般性 , 将适用于所有的子类) 。
3.信息和与之相关的行为应放在同一个类中 。 这实现了面向对象原则中的封装 , 数据和操作数据的处理应包装在一个内聚单元中 。
4.某个事物的信息应局限于一个类中而不要分布在多个类中 。 通常应由一个单独的类负责保存和操作某特定类型的信息 。 通常这个职责不应由多个类分担 。 如果信息是分布的 , 软件将变得更加难以维护 , 测试也会面临更多挑战 。


推荐阅读