2007
年
3
月
22
日星期四
第四
章
责任
责任是什么
虽然作者在第一章就介绍了责任,然而在这一章作为对责任的单独论述,给出了关于责任更加详细的说明:责任是关于软件对象的一般声明,它们主要包括以下
3
个方面:
l
对象执行的动作。
l
对象持有的信息。
l
能够影响到其他对象的决定。
以下内容位于第
117
页
维护信息的责任意味着:
l
对象直接持有信息(作为对象的属性)
l
可以从其他地方获得信息
l
当被请求时,它可以与协作者共同完成任务并且返回信息(负责将结果反馈给其他对象)。
责任并不涉及任何具体的实现方法。当我们说一个对象持有某一信息时,并非意味着在实现细节上它就直接存储有关信息的数据。
责任与实现
Ø
当实现一个具体对象时,你将创建代表对象责任的抽象类和具体类
Ø
隐含在接口中的设计思路是:单一角色可以由多个不同类型的对象实现,而不管它们的具体实现方式。
Ø
对象之间可能从事相似工作,可实现方法不同,你需要考虑如下
3
中情况的区别:承担共同责任,且实现也必须相同;承担共同责任,但需要不同的实现;看似承担了共同的责任,实际上却不是。
责任来自哪里
P93
我们给对象分配责任的策略很简单:覆盖到所有重要的方面。寻找需要执行的动作以及需要维护和生成的信息。
我们可以考虑如下几种获得责任的方法:
1)
确认系统责任声明或将其隐含在用例中。用例
说明了软件系统的行为以及用户如何与其交互,对软件系统的功能进行了粗线条的描述,却并不说明所有这些功能是如何实现的。责任是对象所知、所作和所能判断的一般声明。具体的用例转责任的步骤如下:
l
识别系统所做的事和所掌控的信息
l
将这些事和信息抽象成责任
l
需要的话,将责任划分成更小的部分,并分配给合适的对象。
2)
通过添加低级别的责任来弥补用例和系统描述之间的沟壑
3)
从设计主题和设计提纲中提炼出额外的系统行为
4)
遵循“
what if
…
then
…
and how
”的推理链
5)
识别匹配对象角色的构造型责任
6)
搜寻每个候选对象的更深层本质特征
7)
识别出支持对象之间的关联和从属依赖的责任
8)
识别出与对象的主要动作相关联的责任
9)
识别出对象是和特定软件环境所具备的技术责任
P93
识别责任的方法主要归为以下三类:从客观描述中发现它们、独立的创造它们和从显示的业务建模中添加细节来完善他们。
举例:
MVC
摘自
Pattern-Oriented Software Architecture(John Wiey,1996)
对于
MVC
角色的各项责任的描述。
Model
l
代表一个与应用相关的对象,可以被修改和显示
l
独立于
View
对象和
Controller
对象
l
发生状态改变后会通知其他相关对象
View
l
创建并且初始化与它关联的
Controller
l
向用户展现信息
l
执行更新流程
l
从
Model
对象中获得显示信息
Controller
l
接受用户输入,并将输入看成对某种事件的触发
l
把事件转换成对
Model
的服务请求或者对
View
的显示请求
l
如果需要,执行更新流程
2007
年
3
月
23
日星期五
怎样分配责任
l
从一般化的陈述责任开始
要泛化地、一般化地去陈述责任。不要把责任表达成个别的属性或操作。
l
确定描述的正确层次
P108
你对责任的陈述,应该不要多少知识背景就能理解。
l
使用强烈描述
责任描述越强烈,设计就越精准。
l
做一个机会主义者
l
决定对象将如何分割或共同承担一个庞大、复杂的责任
对象履行责任时有
3
种选择,你可以任选其一:
Ø
亲自完成所有的工作
Ø
请求其他对象帮忙完成部分工作(和其他对象协作)——此时,对象之间应该是组合关系
Ø
将整个服务请求委托给另外的帮助对象。
l
确保对象不会超负荷工作
l
将行为与信息关联
即
GRASP
模式中的“信息专家”模式
l
分散系统的智能(
intelligence
)
记住,我们的目标不是为对象均匀的分配智能,而是让它们承担力所能及的责任。
l
将同一事物的信息集中于同一地方
如果有多个对象需要操作同一信息,那么存在以下
3
种可能的解决方案:
Ø
设计一个新对象作为信息的唯一存储仓库。此仓库对象对于需要共享这一信息的对象都是可见的
Ø
某一对象或许已经承担了与该信息相关的责任。在这种情况下,该对象可以承担维护该信息的责任。其他对象需要信息时,可以向它发送请求。
Ø
可能的话,将需要共享信息的对象融合成一个对象。(我觉得这或许意味着已开始的设计就有问题)这意味着将请求信息的行为封装到一个对象中,消除了对象差异。因为,由于过度设计,我们将责任划分的太细,分配给了太多对象。因此,把这些对象融合成更单一、责任更强的对象才是更好的设计选择。
下面作者给的这个例子相当经典,我以前在设计对象时,就存在这样的误区,而且大多数我身边的初级建模者都会考虑单据上有什么,设计的对象就要包含什么属性。
仅仅因为“顾客名”会出现在发票单上,就认为“发票单”对象应该持有顾客名信息这是不正确的。当需要打印的时候,它可以通过向协作对象发送请求来去的顾客名。
l
保持对象的责任连贯一致
对象的所有责任应该相互关联,并且符合对象所扮演的角色。对象作为整体,应该是责任的总和。各个责任之间应有一种相互补充的关系。对象所知、所做的一切应该都服务于它的使命以及设计模型。
l
将对象的责任约束到单一领域中
l
避免承担非本质责任
l
不要重复责任
除非系统有明确的冗余要求,否则没有必要让多个对象负担着相同而重复的责任。