GRASP原则
GRASP: 基于职责设计对象
职责和职责驱动式设计
思考软件对象设计以及大型构件的流行方式是,考虑其职责(R)、角色(C)和协作(C)
在RDD中,我们认为软件对象具有职责,即对其所作所为的抽象,UML将职责定义为”类元的契约或义务“。就对象的角色而言,职责和对象的义务和行为相关,职责分为行为职责和认知职责。
- 行为职责
- 自身执行的一些行为,如创建对象或者计算;
- 初始化其他对象的动作;
- 控制和协调其他对象的活动;
- 认知职责
- 对私有封装数据的认知;
- 对相关对象的认知;
- 对其能够导出或者计算的事物和认知;
模式
模式是指有经验的OO开发者建立的既有通用原则,又有惯性方案的指令系统来指导他们编制软件,以结构化形式对这些问题,解决方案和命名进行描述使其系统化。
创建者
名称:创建者
问题:谁创建了对象A
解决方案:如果以下条件之一为真时,将创建类A实例的职责分配给类B
- B包含或者组成聚集子A
- B记录A
- B紧密使用A
- B具有A的初始化数据
Note:创建者帮助我们在设计软件时,对象的创建这一职责如何分配的问题
信息专家
名称:信息专家
问题:给对象分配职责的基本原则是什么
解决方案:把职责分配给具有完成该职责所需信息的那个类
Note:信息专家告诉我们在考虑分配职责时考虑谁拥有资源
低耦合
名称:低耦合
问题:如何减少因变化而产生的影响?
解决方案:分配职责以使(不必要的)耦合保持在较低的水平。用该原则可以对可选方案进行评估。
Note:降低依赖性,降低耦合,使得对于需求变化产生时,需要的改动最小。
控制器
名称:控制器
问题:在UI层之上首先接收和协调系统操作的对象是什么?
解决方案:把职责分配给能代表下列选择之一的对象
- 代表全部系统,根对象,运行软件的设备或者是主要的子系统(外观控制器的所有变体)
- 代表发生系统操作的用例场景(用例或会话控制器)
Note:增加可复用性,接口可插拔的潜力。
高内聚
名称:高内聚
问题:如何使得对象保持内聚,可理解,可管理,同时具有支持低耦合的附加作用
解决方案:职责分配应该保持高内聚,依此来评估备选方案
Note:少数情况下,接受低内聚:将一组职责或代码放入一个类或者构件中,以使得某个人能方便地进行对其的维护。
高内聚的优点是支持低耦合,简化维护和改进工作。同时,内聚的类可以用于某个特定的目的,因此细粒度,相关性强的功能的重用性也得到了提高。
多态
名称:多态
问题:如何处理基于类型的选择,如何创建可插拔的软件构件。
- 基于类型的选择。条件变化,如何使用
if-then-else
或者是case
语句的条件逻辑来设计程序,当出现新的变化时,就需要修改这些case逻辑,这种逻辑分布在程序的各个角落,就很难进行变化。 - 可插拔软件构件。客户-服务器关系中的可视化构件,如何才能够替换服务器构件而不对客户端产生影响。
解决方案:当相关选择或者行为随着类而有所不同时,使用多态操作作为变化的行为类型分配职责。
不要测试对象的类型,也不要使用条件逻辑来执行基于类型的不同选择。
Note:解决大量使用条件判断后,代码难以变化的问题,解决服务端可插拔软件问题。
纯虚构
名称:纯虚构
问题:不希违背高内聚和低耦合或者其他目标,但是基于专家模式所提供的方案有不合适时,分配职责
解决方案:对人为制造的类分配一组高内聚的职责,该类并不代表问题领域的概念——只是个虚构的事物,从而来支持高内聚,低耦合和复用。
Note:null
间接性
名称:间接性
问题:为了避免两个或者多个事物之间直接耦合
解决方案:将职责分配给中介对象,使其作为其他构件和服务之间的媒介,以避免他们之间直接耦合。
Note:大多数情况下是使用了纯虚构的想法
隔离变化
名称:隔离变化
问题:设计对象,子系统和系统,使其内部的变化或者不稳定性不会对其他元素产生不良影响
解决方案:识别预计变化或者是不稳定的地方,分配职责用以在这些变化之外创建稳定的接口。
Note:将不稳定,容易变化的部分隔离出去,需要预测PV。
Tips:
- 让客户尽量参与。敏捷开发的原则之一是在整个项目过程中,业务人员和开发者必须每天在一起共同工作。
- 在实际设计中,添加上面的设计思想模式,对总体开发设计起到指导的作用,在原则之间发生冲突时,多加权衡。