crc卡片分拣法,是一种对类之间关系进行建模的简单方法,使设计易于理解。通过从文档里提取类定义的常用方法。卡片分拣的过程可以识别类和了解类定义的内容。我们可以在建立概念模型和详细设计,头脑风暴阶段使用。CRC 是类Class,责任responsible,协作collaboration的简称。根据类所要扮演的职责来确定类。
CRC卡片
使用一个例子进行说明,编写一个21点游戏程序
客户提供一个详细的问题描述,也就是21点规则说明
我们开始设计这个系统。包括类、类的职责、类的交互行为
用例,
21点游戏规则
游戏的目标是获得点数最接近或等于21点的手牌。
胜利者需要赢过庄家的手牌并且不能超过21点。
无论桌上有几名玩家,总是和庄家论输赢。
在21点游戏里,2~10的牌的点数就是牌面的数值,A的点数根据玩家的需要可以取1或11点,JQK的点数都是10。
游戏开始时,玩家首先下注,下注的额度是有上限的。
如果你是唯一的玩家,下注后,庄家给你发2张牌,牌面向上,双方都能看到。
庄家给自己发两张牌,一张向上叫明牌,一张向下的叫底牌。
如果有多个玩家,则庄家给每位玩家都是先发一张明牌,庄家给自己发一张底牌,再给每一位玩家和庄家各发一张明牌。
发完两张牌之后,每位玩家自己决定是否要跟多的牌,当对手的牌数满意之后,就停手等待。
停手等待之后,庄家开始加牌,但是不能超过21点。
当你的手牌超过庄家时你赢,当你的手牌点数不及庄家时,庄家赢。
玩家赢,你的手牌超过庄家,并且不能超过21点,或者庄家超过21点。
玩家输,玩家超过21点。
游戏情景
庄家 玩家
庄家洗牌 玩家下注
庄家给自己发牌 玩家拿牌到手里
手牌返回庄家手牌点数 手牌返回玩家手牌点数
庄家发第二张牌 玩家继续要牌
庄家问玩家是否继续要牌 玩家拿牌到手里
庄家询问玩家手牌点数 手牌返回玩家手牌点数
庄家亮牌 玩家增加或减少赌注
庄家分配赌金 玩家亮牌
如何寻找类?
类对象通常对应一个实体名称,用名词表达,所以找出可能成为类的名词。找出所有可能的类然后再逐一筛选。
如何寻找能够成为类的名词?
类由一组相似的对象组成,对象可以是人物,角色,事物,事件,地点。
不能定义为对象的事物,过程和在对象内部封装的单一属性,因为过程可以定义成某个类的操作,属性可以定义成类的成员属性。也就是说他们可以被定义成某个类的组成部分。
从用例中过滤出我们认为重要名词或短语,
游戏的目标是获得点数最接近或等于21点的手牌。
胜利者需要赢过庄家的手牌并且不能超过21点。
无论桌上有几名玩家,总是和庄家论输赢。
在21点游戏里,2~10的牌的点数就是牌面的数值,A的点数根据玩家的需要可以取1或11点,J,Q,K的点数都是10。
游戏开始时,玩家首先下注,下注的额度是有上限的。
如果你是唯一的玩家,下注后,庄家给你发2张牌,牌面向上,双方都能看到。
庄家给自己发两张牌,一张向上叫明牌,一张向下的叫底牌。
如果有多个玩家,则庄家给每位玩家都是先发一张明牌,庄家给自己发一张底牌,再给每一位玩家和庄家各发一张明牌。
发完两张牌之后,每位玩家自己决定是否要更多的牌,当对手的牌数满意之后,就停手等待。
停手等待之后,庄家开始加牌,但是不能超过21点。
当你的手牌超过庄家时你赢,当你的手牌点数不及庄家时,庄家赢。
玩家赢,你的手牌超过庄家,并且不能超过21点,或者庄家超过21点。
玩家输,玩家超过21点。”
可以发现候选类,游戏,点数,21点,手牌,玩家,庄家,2~10,A,J,Q,K,注,明牌,底牌
如何从候选类里找出真正想定义的类?
在候选类里排除以下类,
1.超出问题关注范围的类
2.指代整个系统的类,例如,游戏,21点
3.功能重复的类
4.过于含糊或具体的类,例如,2~10,A,J,Q,K
筛选原则:
保存对象的信息,系统需要保存对象的信息吗?
点数是牌的数值,所以牌需要保存点数信息。
提供所需要的服务,类对象是否对外提供修改属性值的操作?
“玩家首先下注”,那么需要给玩家提供修改赌注的值的方法。
具有多个属性,只有一个属性的类,应该建模为属性
点数,明牌,底牌是只有一个属性的类,他们可以定义成牌的属性。
具有公共属性,类的属性是否为所有实例对象共享?
点数是A,J,Q,K这些牌的公共属性。
具有公共操作,类的操作是否为所有实例对象共享?
所有玩家都有下注的操作。
外部实体,如果产生或使用外部对象的信息,考虑建模为系统类
筛选出来的类:玩家,庄家,赌注,牌,手牌
识别类小结
从原始资料里识别类,找出干系人提交的问题描述中的名词和短语,如果他描述应用领域中的信息或本质,就加入模型。我们应该首先立即找出3至5个主要类,例如,玩家,庄家,牌。
其他来源,例如背景信息调查,用户及干系人提供,分析模式
最好识别出尽可能多的候选类,然后按照他的价值功用进行选择,明确判断后再排除一个类比从不考虑更加合理。
如何找出类的职责?
类的职责是类需要知道信息和要做的事情。例如玩家需要知道自己手里的牌的点数,牌知道牌面的点数。庄家需要完成洗牌和发牌。
类需要做的事情是一个动作,因此职责可以是问题描述里的动词。
首先我们关注牌,从游戏规则和情景中找出与牌相关的描述。
例如,“在21点游戏里,2~10的牌的点数就是牌面的数值,A的点数根据玩家的需要可以取1或11点,JQK的点数都是10。“”
从上文可知,点数,数值是牌的属性,2~10,AJQK是不同类型的牌。
那么牌的职责是
点数,
牌面的数值,
判断是否为数字,
判断是否为A,
判断是否为JQK
再来关注手牌,从游戏规则和情景中找出与手牌牌相关的描述。
“手牌返回庄家手牌点数。庄家亮牌 ”
手牌的职责
计算手牌总点数
添加牌
亮牌
使用相同方法找出赌注的职责
赌注的大小
修改赌注
玩家的职责
请求庄家发牌
亮牌
计算手牌总点数
判断手牌总点数大于21点
判断手牌总点数等于21点
判断手牌总点数小于21点
庄家的职责
发牌
洗牌
加牌
亮牌
计算手牌总点数
判断手牌总点数大于21点
判断手牌总点数等于21点
判断手牌总点数小于21点
确定赢家
开启游戏
庄家职责里出现发牌,洗牌的操作,考虑这样的问题,通过游戏规则我们可以知道,21点游戏最少需要2人参加即庄家和一个玩家开始一轮游戏,如果只有一张牌是不能进行游戏的,需要有多张牌才能玩下去,那么我们需要一副牌这样的概念。一副牌表示牌的集合。
一副牌的职责
发牌
洗牌
查询剩余的牌数
找职责过程中需要注意的问题,
1.不是所有动词都是类的职责
2.有时多个动作可以合并成一个职责
3.随着分析过程深入会发现新的职责
4.不断修正类的定义和职责定义
5.当2个类分享职责的时候,为他们同时添加该职责
如何寻找协作类?
类在执行自己职责的时候发现没有足够的信息来完整这样的操作,因此需要其他的类来帮助他来完成工作。那么协作类可以提供需要信息或者完成任务。
例如,庄家拥有发牌,洗牌的职责,庄家能够独立完成这个职责吗?不能,那么寻找能够完成这个职责的类,发现一副牌类具有这样的职责,那么一副牌类就是庄家类的协作类。
对类中每个职责标示协作者,都应该问问自己,这个类有没有能力自己独立完成这个职责?如果不能就应该寻找另外一个类,或者有能力弥补缺少的设计部分,在这个过程里我们可以发现其他类需要一些新的职责,或者需要设计一些新的类。
CRC分拣法是一种面向对象的分析方法,用来帮助开发者快速从需求里快速找出类,理清类的职责以及类之间关系,为设计概念模型,顺序图,类图提供参考资料。CRC卡片随着分析过程的逐步深入持续精化。主要用于理解和沟通而不是构建文档。因为需求是不断变化的,所以我们针对某一个需求建模。
优点:能够帮助整个团队对对系统形成共识,使用卡片容易对类之间的关系进行分组和测试,使用crc卡片不需要一个完整的设计,非常适合在设计早期阶段使用,例如在设计组件之间关系的时候使用。
缺点:缺乏细节和精确度,不能用来解释一个类是如何工作的。没有属性和方法。他是一个用来帮助理解需求的工具而不是对业务进行优化的工具。不能表示出继承或组合关系。