一
在学会识别对象职责之前,务必时刻牢记“职责”二字,每当你需要为某个类添加方法,或者要在该方法中实现某些业务逻辑时,“职责”二字就必须跳出来提醒你,这里的职责分配合理吗?这是一种设计上的约束,但却是必要的约束,因为只有如此,对象的职能才不会无限的膨胀,对象间的协作才能变得合理,代码才不会变成乱糟糟的意大利面条。如果再上升到软件架构的层次,就需要识别模块、子系统或者层次的职责。职责的分配必须恰如其分,意图营造一个“和谐”的对象社区。在整个系统中,各个组成部分(对象、组件、模块)都能很好地履行自己的职责,良好地表达自己的意图,并能友好地进行协作,进而形成一个完美的整体。
根据Rebecca的著作《面向设计:角色、责任和协作》一书的总结,认为对象履行职责的方式,大约分为如下三种:
亲自完成所有的工作
请求其他对象帮忙完成部分工作(和其他对象协作)
将整个服务请求委托给另外的帮助对象
之所以在软件系统中的对象必须以协作的方式来履行职责,就是因为一个对象不能承担太多的职责,正如一个人不能承担太多的责任一样。职责的分配必须是恰如其分的,“增之一分则太多,减之一分则太少”。一个对象如果把所有的事情都做完,我们就将这样的对象称为“上帝类”。我们需要避免设计这样庞大的类。
为什么?
让我们首先来看看如下的实际案例:在一个Web系统中,我们需要对用户从界面上提交的参数进行处理,它将根据配置文件中的业务规则对参数进行解析,并按照配置信息中设置的参数间依赖关系建立参数的对象图。
我们可以定义这样一个类:
1 | public class ParameterAction { |
2 | public ParameterGraph handle(RequestContext context){ |
3 |
4 | } |
5 | } |
根据需求,事实上可以分辨出如下职责:
对传入的RequestContext进行处理,获得参数集;
读取配置文件中的规则,解析为Parameter对象;
读取配置文件中参数间的依赖关系,生成参数对象图;
我设计的对象间协作的通信图如下所示:
这样的设计会带来什么好处呢?例如,在该系统中,如果除了ParameterAction类需要处理参数之外,还有另外两个类ParameterViewGenerator和ParameterContextWriter需要参数的支持。前者需要读取配置文件,获得参数以生成参数视图,后者则需要单独对参数进行解析。有了良好的对象定义,我们就可以有效地重用ParameterCollector类和ParameterResolver类:
根据如下的例子,我们得出合理分配对象职责的第一个好处:利于重用。