GRASP 九大基本原则
什么是 GRASP
GRASP 是 General Responsibility Assignment Software Patterns 的缩写,即通用职责分配软件模式。有助于合理的分配类的职责,使得设计更加的灵活,易于维护。
九大基本原则
1. 创建者 (Creator)
谁负责创建对象?
B 的实例包括 A 的实例,或是合成聚合 A 的实例
B 的实例会纪录 A 的实例
B 的实例密切的使用 A 的实例
B 的实例有 A 的实例初始化时的信息,在创建对象时会传递给 A 的实例
这个原则更偏向于由谁来创建,而不是有什么职责。
2. 信息专家 (Information Expert)
谁应当拥有职责(功能/函数/方法)?
将职责分配给那些拥有最多必要信息的类
这个原则与 Creator 的区别在于,Creator 是创建对象,而 Information Expert 是拥有职责。(拥有职责是指拥有某个方法,例如获得价格这个方法应当给予收据类而不是顾客类)
3. 低耦合 (Low Coupling)
这是一个评价原则,无法具体的表达。简要来说,就是尽量减少类之间的依赖关系。
4. 高内聚 (High Cohesion)
同上,这也是一条评价原则。简要来说,就是尽量使类内部的方法之间的依赖关系更强。
注意,高内聚和低耦合可能会相互冲突,因此设计的时候需要在两者之间取得平衡。
5. 控制器 (Controller)
谁应当负责处理一个系统操作?
将系统操作的职责分配给一个类,或是一个操作的集合
这个目的是为了降低耦合,令处理系统事件的类独立出来,同时这个原则有着一定的 Pure Fabrication 的感觉。
6. 多态 (Polymorphism)
这一条是面向对象最基本的原则,也是最灵活的部分。基于多态进行设计,可以使得系统更加的灵活,易于扩展。
7. 纯虚构 (Pure Fabrication)
当没有合适的类可以分配职责时,如何做?
创建一个新的类,将职责分配给它
例如我们有个骰子游戏,目前只有两个类:玩家和骰子。那么我们应该把掷骰子方法分配给谁呢?如果分配给玩家,那么玩家类就会变得臃肿,如果分配给骰子,那么骰子类就会变得臃肿。这时候我们就可以创建一个新的类,专门用来处理掷骰子的方法。
这个类的名字可以叫做 DiceRoller,它不是一个真实的类,而是一个纯虚构的类,它的存在只是为了分配职责。
8. 中介 (Indirection)
如何降低类之间的耦合?
将类之间的依赖关系转换为间接的依赖关系,通过一个中介类来实现。
最经典的案例:
软件需要打印 Log,最经典的 Log 类是 Log4j,但是如果我们直接在代码中使用 Log4j,那么我们的代码就会和 Log4j 产生依赖关系,这样就会导致我们无法更换 Log4j。
有人可能会问了:不换就不换嘛,有什么大不了的。
在 2021 年,Log4j 被发现一个致命漏洞,这个漏洞可以让攻击者通过 Log4j 来执行任意代码。此时使用了 Indirection 原则的项目,程序员乐开了花,只要更换以下中介类就可以了,而没有使用 Indirection 原则的项目,程序员都哭了,因为他们需要手动更换代码中所有的 Log4j 调用部分。
9. 保护变异 (Protected Variations)
如何保护系统免受变化的影响?
将可能变化的部分封装起来,使得变化不会影响到其他部分。
即:基于一定设计使不稳定因素不影响外界
还是上面那个例子,如果我们使用了 Indirection 原则,那么我们只需要更换中介类就可以了,而不需要更换代码中所有的 Log4j 调用部分。这就是保护变异原则。
中介的思想来自于低耦合,低耦合思想来自于保护变异。因此保护变异是最核心的原则