GRASP (职责分配原则)

要学习设计模式,有些基础知识是我们必须要先知道的,设计模式是关于类和对象的一种高效、灵活的使用方式,也就是说,必须先有类和对象,才能有设计模式的用武之地,否则一切都是空谈,那么类和对象是从那冒出来的呢?这时就需要比23种设计模式更重要更经典的GRASP模式登场了,嘿嘿,原来这才是老大!

GRASP(General Responsibility Assignment Software Patterns),中文名称为“通用职责分配软件模式”,GRASP一共包括9种模式,它们描述了对象设计和职责分配的基本原则。也就是说,如何把现实世界的业务功能抽象成对象,如何决定一个系统有多少对象,每个对象都包括什么职责,GRASP模式给出了最基本的指导原则。初学者应该尽快掌握、理解这些原则,因为这是如何设计一个面向对象系统的基础。可以说,GRASP是学习使用设计模式的基础。

1. Information Expert (信息专家)

信息专家模式是面向对象设计的最基本原则,是我们平时使用最多,应该跟我们的思想融为一体的原则。也就是说,我们设计对象(类)的时候,如果某个类拥有完成某个职责所需要的所有信息,那么这个职责就应该分配给这个类来实现。这时,这个类就是相对于这个职责的信息专家。

例如:常见的网上商店里的购物车(ShopCar),需要让每种商品(SKU)只在购物车内出现一次,购买相同商品,只需要更新商品的数量即可。如下图:

(SKUID)来唯一区分商品,而商品编号是唯一存在于商品类里的,所以根据信息专家模式,应该把比较商品是否相同的方法放在商品类里。

2. Creator (创造者)

实际应用中,符合下列任一条件的时候,都应该由类A来创建类B,这时A是B的创建者:

a. A是B的聚合

b. A是B的容器

c. A持有初始化B的信息(数据)

d. A记录B的实例

e. A频繁使用B

如果一个类创建了另一个类,那么这两个类之间就有了耦合,也可以说产生了依赖关系。依赖或耦合本身是没有错误的,但是它们带来的问题就是在以后的维护中会产生连锁反应,而必要的耦合是逃不掉的,我们能做的就是正确地创建耦合关系,不要随便建立类之间的依赖关系,那么该如何去做呢?就是要遵守创建者模式规定的基本原则,凡是不符合以上条件的情况,都不能随便用A创建B。

例如:因为订单(Order)是商品(SKU)的容器,所以应该由订单来创建商品。如下图:

3. Low coupling (低耦合)

低耦合模式的意思就是要我们尽可能地减少类之间的连接。

其作用非常重要:

a. 低耦合降低了因一个类的变化而影响其他类的范围。

b. 低耦合使类更容易理解,因为类会变得简单,更内聚。

下面这些情况会造成类A、B之间的耦合:

a. A是B的属性

b. A调用B的实例的方法

c. A的方法中引用了B,例如B是A方法的返回值或参数。

d. A是B的子类,或者A实现了B

关于低耦合,还有下面一些基本原则:

a. Don’t Talk to Strangers原则:

意思就是说,不需要通信的两个对象之间,不要进行无谓的连接,连接了就有可能产生问题,不连接就一了百了啦!

b. 如果A已经和B有连接,如果分配A的职责给B不合适的话(违反信息专家模式),那么就把B的职责分配给A。

c. 两个不同模块的内部类之间不能直接连接,否则必招报应!嘿!

例如:Creator模式的例子里,实际业务中需要另一个出货人来清点订单(Order)上的商品(SKU),并计算出商品的总价,但是由于订单和商品之间的耦合已经存在了,那么把这个职责分配给订单更合适,这样可以降低耦合,以便降低系统的复杂性。如下图:

TotalPrice()方法来执行计算总价的职责,没有增加不必要的耦合。

4. High cohesion (高内聚)

高内聚的意思是给类尽量分配内聚的职责,也可以说成是功能性内聚的职责。即功能性紧密相关的职责应该放在一个类里,并共同完成有限的功能,那么就是高内聚合。这样更有利于类的理解和重用,也便于类的维护。

高内聚也可以说是一种隔离,就想人体由很多独立的细胞组成,大厦由很多砖头、钢筋、混凝土组成,每一个部分(类)都有自己独立的职责和特性,每一个部分内部发生了问题,也不会影响其他部分,因为高内聚的对象之间是隔离开的。

例如:一个订单数据存取类(OrderDAO),订单即可以保存为Excel模式,也可以保存到数据库中;那么,不同的职责最好由不同的类来实现,这样才是高内聚的设计,如下图:

Excel的功能发生错误,那么就去检查OrderDAOExcel类就可以了,这样也使系统更模块化,方便划分任务,比如这两个类就可以分配个不同的人同时进行开发,这样也提高了团队协作和开发进度。 

5. Controller (控制器)

用来接收和处理系统事件的职责,一般应该分配给一个能够代表整个系统的类,这样的类通常被命名为“XX处理器”、“XX协调器”或者“XX会话”。

关于控制器类,有如下原则:

a. 系统事件的接收与处理通常由一个高级类来代替。

b. 一个子系统会有很多控制器类,分别处理不同的事务。

关于这个模式更详细的论述,请参考《UML和模式应用》第16章。

6. Polymorphism (多态)

这里的多态跟OO三大基本特征之一的“多态”是一个意思。

例如:我们想设计一个绘图程序,要支持可以画不同类型的图形,我们定义一个抽象类Shape,矩形(Rectangle)、圆形(Round)分别继承这个抽象类,并重写(override)Shape类里的Draw()方法,这样我们就可以使用同样的接口(Shape抽象类)绘制出不同的图形,如下图:

(Diamond)类,对整个系统结构也没有任何影响,只要增加一个继承Shape的类就行了。 

7. Pure Fabrication (纯虚构)

这里的纯虚构跟我们常说的纯虚构函数意思相近。高内聚低耦合,是系统设计的终极目标,但是内聚和耦合永远都是矛盾对立的。高内聚以为这拆分出更多数量的类,但是对象之间需要协作来完成任务,这又造成了高耦合,反过来毅然。该如何解决这个矛盾呢,这个时候就需要纯虚构模式,由一个纯虚构的类来协调内聚和耦合,可以在一定程度上解决上述问题。

例如:上面多态模式的例子,如果我们的绘图程序需要支持不同的系统,那么因为不同系统的API结构不同,绘图功能也需要不同的实现方式,那么该如何设计更合适呢?如下图:

AbstractShape,不论是哪个系统都可以通过AbstractShape类来绘制图形,我们即没有降低原来的内聚性,也没有增加过多的耦合,可谓鱼肉和熊掌兼得,哈哈哈!

8. Indirection (间接)

“间接”顾名思义,就是这个事不能直接来办,需要绕个弯才行。绕个弯的好处就是,本来直接会连接在一起的对象彼此隔离开了,一个的变动不会影响另一个。就想我在前面的低耦合模式里说的一样,“两个不同模块的内部类之间不能直接连接”,但是我们可以通过中间类来间接连接两个不同的模块,这样对于这两个模块来说,他们之间仍然是没有耦合/依赖关系的。

9. Protected Variations (受保护变化)

预先找出不稳定的变化点,使用统一的接口封装起来,如果未来发生变化的时候,可以通过接口扩展新的功能,而不需要去修改原来旧的实现。也可以把这个模式理解为OCP(开闭原则)原则,就是说一个软件实体应当对扩展开发,对修改关闭。在设计一个模块的时候,要保证这个模块可以在不需要被修改的前提下可以得到扩展。这样做的好处就是通过扩展给系统提供了新的职责,以满足新的需求,同时又没有改变系统原来的功能。关于OCP原则,后面还会有单独的论述。

这里我们可以看到,因为增加了纯虚构类

这样的设计更符合高内聚和低耦合原则,虽然后来我们又增加了一个菱形

这里我们把两种不同的数据存储功能分别放在了两个类里来实现,这样如果未来保存到

这里我们在订单类里增加了一个

这里因为订单是商品的容器,也只有订单持有初始化商品的信息,所以这个耦合关系是正确的且没办法避免的,所以由订单来创建商品。

针对这个问题需要权衡的是,比较商品是否相同的方法需要放到那里类里来实现呢?分析业务得知需要根据商品的编号

我们生活在一个充满规则的世界里,在复杂多变的外表下,万事万物都被永恒的真理支配并有规律的运行着。模式也是一样,不论那种模式,其背后都潜藏着一些“永恒的真理”,这个真理就是设计原则。记得一次参加微软的架构师培训,期间讲到设计模式,有人问了老师一个问题:“什么东西比设计模式更重要?”,老师是一位有多年丰富实践经验的开发者,他毫不犹豫地回答到:“比模式更重要的是原则”。这句话我时常能够想起,越来越觉得这是一个伟大的答案。的确,还有什么比原则更重要呢?就像人的世界观和人生观一样,那才是支配你一切行为的根本,而对于设计模式来说,为什么这个模式要这样解决这个问题,而另一个模式要那样,它们背后都遵循的就是永恒的设计原则。可以说,设计原则是设计模式的灵魂。

对于设计原则的深入探讨我还没有那个深度,推荐大家去看《敏捷软件开发—原则、模式与实践》,下面仅对部分常用的设计原则做些简单的讲解:

(转载)GRASP职责分配原则的更多相关文章

  1. GRASP (职责分配原则)

    要学习设计模式,有些基础知识是我们必须要先知道的,设计模式是关于类和对象的一种高效.灵活的使用方式,也就是说,必须先有类和对象,才能有设计模式的用武之地,否则一切都是空谈,那么类和对象是从那冒出来的呢 ...

  2. Atitit GRASP(General Responsibility Assignment Software Patterns),中文名称为“通用职责分配软件模式”

    Atitit GRASP(General Responsibility Assignment Software Patterns),中文名称为"通用职责分配软件模式" 1. GRA ...

  3. 【转】 GRASP(通用职责分配软件模式)模式

    转自:http://www.cnblogs.com/sevenyuan/archive/2010/03/05/1678730.html 及:http://blog.csdn.net/lovelion ...

  4. Teamwork-Week3 职责划分及团队分数分配原则

    本组人数:5. 一.人员职责划分 PM:1            柴泽华 PM的职责: 1)根据项目范围.质量.时间与成本的综合因素的考虑,进行项目的总体规划与阶段计划. 2)设置项目组中的各种角色, ...

  5. Java虚拟机7:内存分配原则

    前言 对象的内存分配,往大的方向上讲,就是在堆上分配,少数情况下也可能会直接分配在老年代中,分配的规则并不是百分之百固定的,其细节决定于当前使用的是哪种垃圾收集器组合,当然还有虚拟机中与内存相关的参数 ...

  6. Java虚拟机11:内存分配原则

    前言 JVM的自动内存管理要自动化的解决两个问题:对象分配内存以及回收分配给对象的内存.对象的内存分配一般是指在堆上分配,少数情况下也可能会直接分配在老年代上,对象主要分配在新生代的Eden 区上,如 ...

  7. GRASP职责分配模式

    https://mp.weixin.qq.com/s/IaxAnWfVqe3mM0bHFVV5Gg 软件开发必修课:你该知道的GRASP职责分配模式 原创 悟真 阿里技术 今天 收录于话题 #设计模式 ...

  8. 设计原则:单一职责(SRP)原则

    1 什么是单一职责(SRP)原则 单一职责原则的英文是 Single Responsibility Principle,缩写为 SRP.翻译过来就是:一个类或者模块只负责完成一个职责(或者功能). 所 ...

  9. 7.1 通用的职责分配软件原则 GRASP原则一: 创建者 Creator

    1.GRASP原则一: 创建者 Creator  Who should be responsible for creating a new instance of some class 由谁来负责创 ...

随机推荐

  1. centos mysql忘记密码找回(仅限mysql5.7)

    1.停掉mysql 2.执行#mysqld_safe --user=mysql --skip-grant-tables --skip-networking & 3.#mysql 4.updat ...

  2. js练习计算器

    js练习计算器,支持鼠标点击.键盘操作 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" &quo ...

  3. TFS (Team Foundation Server) 2013集成Maven构建

    Team Foundation Server原生就支持跨平台的构建,包括Ant和Maven两种构建方式.通过配置构建服务器,连接TFS源代码库,可以实现持续集成构建,自动检测代码库健康状况,进而实现自 ...

  4. 不错的Django博客

    https://blog.csdn.net/chengqiuming/article/category/8453874 杜塞的个人网站 https://www.dusaiphoto.com/ 追梦人物 ...

  5. ajax 与 form 提交的区别

    有如下几种区别: 1. Ajax在提交.请求.接收时,都是异步进行的,网页不需要刷新:Form提交则是新建一个页面,哪怕是提交给自己本身的页面,也是需要刷新的: 2. A在提交时,是在后台新建一个请求 ...

  6. Git命令行学习积累

    1.远程分支拉取到本地 $ git checkout -b develop origin/develop //检出远程的develop分支到本地 2.本地分支推送到远程 $ git checkout ...

  7. 【转】Leader-Follower线程模型

    上图就是L/F多线程模型的状态变迁图,共6个关键点: (1)线程有3种状态:领导leading,处理processing,追随following (2)假设共N个线程,其中只有1个leading线程( ...

  8. .Net Core MVC初学习

    .net core已经出来很长一段时间了,没有很好的学习过,现在工作不那么忙了,参考官方文档,在这里记录自己的学习过程! ASP.NET Core 是一个跨平台的高性能开源框架,用于生成基于云且连接 ...

  9. iOS 错误 undefined symbols for architecture i386

    undefined symbols for architecture i386 这个错误困扰了我几个小时. 网上很多问这个问题的,回答基本上都是说在 target 里面去的 armv64 什么什么的. ...

  10. 初识Mybatis框架

    mybatis框架  主要是对数据库进行操作的 编写sql语句 使我们对数据库的crud操作更加简洁方便!! 1.使用mybatis框架 进行第一个项目 查询数据库 并返回数据 :(简单) (1)搭建 ...