一:GRASP软件开发模式

<1>Craig Larman在《Applying UML and Patterns》一书中提出了GRASP设计模式的概念。

<2>作者称其为设计模式,其实,更好的理解应该为设计原则。

<3>GoF设计模式是针对特定问题而提出的解决方法。

<4>GRASP则是站在面向对象设计的角度,告诉我们怎么样设计问题空间中的类与它们的行为责任,以及明确类之间的相互关系等等。

<5>GRASP可以说是GoF等设计模式的基础。

<6>GRASP:
General Responsibility Assignment Software patterns
通用职责分配软件模式

<7>核心思想:
“职责分配(Responsibility Assignment)”
用职责设计对象:"Designing Objects with Responsibilities“

<8>进一步理解核心思想:
自己干自己的事(职责的分配)
自己干自己的能干的事(职责的分配)
自己只干自己的事(职责的内聚)

五个基本模式

1、信息专家(Information expert)
2、创建者(Creator)
3、高内聚(High Cohesion)
4、低耦合(Low coupling)
5、控制器(Controller)

四个扩展模式

6、多态性(Polymorphism)
7、纯虚构(Pure Fabrication)
8、间接性(Indirection)
9、防止变异(Protected Variations)

二:信息专家(Information expert)

GRASP模式中解决类的职责分配问题的最基本的模式。

问题
当我们为系统发现完对象和职责之后,职责的分配原则(职责将分配给哪个对象执行)是什么?

解决方案
1、职责的执行需要某些信息(information),把职责分配给该信息的拥有者。换句话说,某项职责的执行需要某些资源,只有拥有这些资源的对象才有资格执行职责。 --“有能者为之”

2、满足了面向对象设计的封装性的设计,一般情况下都会满足Information Expert模式。因为Information Expert是对类的属性(信息),以及对类的属性的操作的封装,它符合对象封装性的概念。

优点
1、信息的拥有者类同时就是信息的操作者类,可以减少不必要的类之间的关联。
2、各类的职责单一明确,容易理解。

三:创建者(Creator)

GRASP模式中解决类的实例的创建职责问题的模式。

问题
类的实例的创建职责,应该分配给什么样的类?或者说类的实例应该由谁创建?

解决方案
以下条件之一为真的情况,类A的实例的创建职责就分配给类B。
1、B包含A
2、B聚集A
3、B记录A
4、B频繁使用A
5、B有A初始化数据

提倡类的实例(对象)创建职责由聚集或包含该对象的对象创建

优点
1、整个结构清晰易懂
2、有利于类或组件的重用
3、防止职责的分散
4、降低耦合性

四:高内聚(High Cohesion)

GRASP模式中为降低类的复杂程度,简化控制而提出的面向对象设计的原则性模式。高内聚(High Cohesion)与低耦合(Low Coupling)模式是GRASP其他模式的根本。

问题
怎么做才能降低类的复杂程度,简化控制?

解决方案
紧密相关的功能(职责)应该分配给同一个类。–“各司其职”

所谓内聚,是指单个物体(类)内部的功能聚集度。比如,只包含有相互关联的功能的类,具有高内聚性,同时,它的外部表现(作用,意图)也就明显;反之,如果一个类由一些不相关的功能构成,它的内聚性就低,它的外部表现就不明显,一方面很难理解它的作用和意图,另一方面,一旦需求变化,扩展性就差。

优点
1、聚集相关功能,结构清晰,容易理解
2、只聚集相关功能,使得类的职责单一明确,从而降低类的复杂程度,使用简单

五:低耦合(Low coupling)

GRASP模式中为降低类的复杂程度,简化控制而提出的面向对象设计的原则性模式。高内聚(High Cohesion)与低耦合(Low Coupling)模式是GRASP其他模式的根本。

问题
怎么做才能降低类之间关联程度,能适应需求的变化呢?

解决方案
为类分配职责时,应该尽量降低类之间的关联关系(耦合性)。亦即,应该以降低类之间的耦合关系作为职责分配的原则。

所谓耦合,是指多个物体(类)之间的物理或者意思上的关联程度。在面向对象方法中,类是最基本的元素,耦合主要指不同类之间相互关联的紧密程度。面向对象里的关联,主要指一个类对另一个类的调用,聚合(包含),参数传递等关系。比如,所谓2个关联得非常紧密的类(高耦合),是指其中一个类发生变化(修改)时,另一个类也不得不跟着发生变化(修改)。

面向对象设计要求类之间满足“低耦合”原则,它是衡量一个设计是否优良的的一个重要标准,因为“低耦合”有助于使得系统中某一部分的变化对其它部分的影响降到最低程度。

优点
1、一方面,高内聚要求把紧密关联的功能(职责)聚集在同一个类中,防止功能的扩散和类的无谓增加,从而减少类之间的关联,降低类之间的发生耦合的机率。

2、另一方面,高内聚要求把不相关的功能分散到不同的类,类增加了,势必造成相互关联类的增加,从而增大类之间发生耦合的机率。

六:控制器(Controller)

GRASP模式中解决事件处理职责问题的模式。

问题
在UI层之外,应该由哪个类来处理(控制)系统操作(事件)呢?或者说,当触发一个系统事件时,应该把对事件的处理职责分配给UI层之外的哪个类呢?

解决方案
把系统事件的处理职责分配给Controller(控制器)类。

Controller模式提倡用一个专门的类来处理所有的系统事件。或者说Controller模式把所有系统事件的处理职责分配给一个专门的类集中处理。

优点
1、防止同类职责的分散。满足高内聚,低耦合原则。
2、有利于共通处理(前处理,后处理等)。
3、变化的高适应能力。能够把变化的修改范围控制在最小范围(控制器)之内。

七:多态性(Polymorphism)

问题
如何处理基于类型的选择?如何创建可插拔的软件构件?

解决方案
当相关选择或行为随类型(类)有所不同时,使用多态操作为变化的行为类型分配职责。

八:纯虚构(Pure Fabrication)

问题
当你并不想违背高内聚和低耦合或其它目标,但是基于专家模式所提供的方案又不合适时,哪些对象应该承担这一职责?(很多情况下,只对领域对象分配职责会导致不良内聚或耦合,或者降低复用潜力)

解决方案
对人为制造的类分配一组高内聚的职责,该类并不代表问题领域的概念——虚构的事物,用以支持高内聚,低耦合和复用。

所有GOF设计模式(或其它模式)都是纯虚构。

九:间接性(Indirection)

问题
为了避免两个或多个事物之间的直接耦合,应该如何分配职责?如何使对象解耦合,以支持低耦合并提供复用性潜力?

解决方案
将职责分配给中介对象,避免它们之间的直接耦合。中介实现了间接性。
大量GOF模式,如适配器、外观等等都是间接性的体现。

十:防止变异(Protected Variations)

问题
如何设计对象、子系统和系统,使其内部的变化或不稳定性不会对其它元素产生不良影响?

解决方案
识别预计变化或不稳定之处,分配职责用以在这些变化之外创建稳定接口。

几乎所有的软件或架构设计技巧,都是防止变异的特例,比如封装、多态、接口、虚拟机、配置文件等。

十一:防止变异的核心机制

1、数据驱动设计(Data-Driven Design):通过外置、读取并判断变化因素,防止数据、元数据或说明性变量等对系统产生影响。
2、服务查询(Service Lookup):Data-Driven Design的特例,如JNDI,UDDI,通过使用查询服务的稳定接口,客户能够避免服务位置变化的影响。
3、解释器驱动的设计(Interpreter-Driven Design):系统通过外置、读取、解释逻辑而避免了逻辑变化的影响。
4、反射或元级的设计(Reflective or Meta-Level Design)可避免逻辑或外部代码变化的影响
5、统一访问(Uniform Access):如C#中的XXX.Name
6、标准语言(Standard Language)
7、Liskov替换原则(LSP):在对T有任何替换实现或子类(成为S)情况下,引用类型T(某接口或抽象超类)的软件(方法,类……)应该正常或按照预期工作。
8、得墨忒耳定律(Law of Demeter):不要经历远距离的对象结构路径去向远距离的间接对象发送消息。
9、开放-封闭原则(OCP):模块应该同时(对扩展、可适应性)开放和(对影响客户的更改)封闭。

十二:GRASP软件开发模式-总结

GRASP和GoF都是称为软件开发模式,只是描述的内容和角度不同。

GRASP和GoF是不同类型的模式,出发点不同。GRASP是解决类之间如何交互,如何设计合理,和具体问题无关。

GoF往往是解决一些具体的问题,比如类的具体创建方式等等,而GRASP是解决对象分析的一些基本原则,即你如何去设计你的问题空间中的类和它们的行为,是原则性的东西。

GRASP适用于对象分析和设计中,即在RUP的制作分析模型和设计模型阶段,GoF更适用于在实际编码过程中作为更加具体的指导思想。