GRASP设计原则
GRASP设计原则
- 介绍
- 9种基本原则
- 创建者 Creator
- 问题
- 解决方法
- 何时不使用?
- 好处
- 信息专家 Information Expert
- 问题
- 解决方法
- 信息
- 怎么做
- 优点
- 低耦合 Low Coupling
- 耦合
- 问题
- 解决方法
- 原则
- 何时不使用?
- 控制器 Controller
- 问题
- 解决方法
- 外观控制器
- 会话控制器
- 优点
- 臃肿控制器的解决方法
- 高内聚 High Cohesion
- 问题
- 解决办法
- 用法
- 衡量概念之间相关度的两个指标
- 内聚的最佳实践
- 类低内聚
- 多态 Polymorphism
- 问题
- 解决办法
- 推论
- 纯虚构 Pure Fabrication
- 问题
- 解决办法
- 推论
- 原则
- 风险
- 间接 Indirection
- 问题
- 解决办法
- 隔离变化
- 问题
- 解决办法
- 变化点的分类
介绍
GRASP(General Responsibility Assignment Software Pattern)是通用职责分配软件设计模式,它可以帮助设计人员理解面向对象设计的本质,并以一种有条理的、理性的、可解释的方式来运用这些原则。由《UML和模式应用》(Applying UML and Patterns)一书作者Craig Larman提出。
在面向对象设计的过程中一般的通用方式是构思对象的职责、角色和协作。通常来说,我们在编码过程中先分析问题域,从中抽象出对象解决问题。简单的面向对象和优秀的面向对象设计的区别在于如何更合理的划分对象的角色,给对象赋予合理的职责以及对象之间的交互关系。
GRASP是对象职责分配的基本原则,其核心思想是职责分配,用职责设计对象。
9种基本原则
- 创建者(Creator)
- 信息专家(Information Expert)
- 低耦合(Low coupling)
- 控制器(Controller)
- 高内聚(High Cohesion)
- 多态性(Polymorphism)
- 纯虚构(Pure Fabrication)
- 间接性(Indirection)
- 隔离变化(Protected Variations)
这些模式都是针对软件开发上的一些问题进行解决。发明这些技巧不是为了要创造新的工作方式,而是为在面向对象设计上,对经过测试的程序设计方式创建文档并且标准化。
Craig Larman提到:“软件开发最关键的设计工具不是UML或其他的技术,是明了设计原则的心智。”。因此,GRASP原则是心理层面的工具集,是面向对象软件设计学习的辅助工具。
创建者 Creator
问题
谁负责创建类的实例?
解决方法
满足下面一个选项,则由B来创建A:
- B包含,聚集A
- B记录A
- B紧密使用 A
- B拥有A的初始化数据
若有一个以上的选项适用,则首选包含或聚集A的类。
注意:A和B都是软件对象,而不是领域对象。
何时不使用?
- 出于性能目的(缓存)而重用类的实例
- 有些情况下要基于某些外部属性值从一个相似类的家族创建一个实例(抽象工厂模式)
- 委托职责向下传递
- 其他复杂情况
好处
- 使用方便
- 高内聚
- 低耦合
信息专家 Information Expert
问题
为一个对象分配职责的一般性原则是什么?
解决方法
若这个类拥有完成这个职责所需要的数据,则把这个职责分配给这个类。
信息
- 一个对象拥有的状态
- 和一个对象相关的其他对象
- 一个对象派生的信息
- 等等
怎么做
- 明确地表达职责
- 在设计模型中查看相关的类
- 在领域模型中查看并创建设计类
优点
封装性:对象充分利用自身的信息,低耦合
系统行为分布到不同的类:高内聚
低耦合 Low Coupling
耦合
- 耦合的定义
一个元素和另一个元素的连接,感知和依赖程度。
- 比较
内聚:模块内的元素之间紧密程度,如一个类内部操作之间。
耦合:两个子模块之间的紧密程度,如两个类之间的操作。
- 高耦合带来的问题
- 牵一发动全身
- 元素孤立是无法理解
- 元素很难重用
- X与Y存在耦合的情况,例如:
- X拥有Y的属性
- X调用Y的服务
- X有Y的成员变量,方法参数和局部变量
- X是Y的子类
- Y是接口,X实现接口
问题
如何保证设计方案支持低依赖性,低变化影响度和增加可重用性?
解决方法
分配职责后仍然保持低耦合。
原则
- 低耦合不具备可操作性,是一个评估原则,如:若两个方案都可以的,倾向于选择低耦合的方案。继承关系中,子类与父类的耦合非常紧密,如:能用组合的不要用继承。
- 类之间存在适当的耦合是必须的,正常的。因为只有这样才产生面向对象系统,任务才能通过对象间的相互协作来完成。
- 不能单独考虑低耦合,极端情况:类之间没有耦合。这样会形成一个很差的设计,一个类来完成全部的工作。
- 低耦合与其他原则,如信息专家、高内聚必须综合考虑。
何时不使用?
若是稳定的或广为流传的,可以有高耦合,如Java的jdk,软件系统可以和jdk高耦合。
控制器 Controller
问题
在领域层,由谁负责首先接收并协调来自UI层的系统操作?
解决方法
- Facade(外观) Controller:代表整个系统的对象,如一个根对象,一个系统运行的设备或一个主要的子系统。
- Use Case or Session Controller(用例控制器、会话控制器):代表一类系统事件产生的用例场景。
外观控制器
相当于领域层对外部世界的“脸”。适用于:
- 相对较小的系统
- 有限数量的系统操作
- 在消息处理系统中,不能转发消息到可选的控制器时
会话控制器
处理系统某个明确的功能集,比如相关的一组系统事件。适用于:
- 当采用外观控制器会导致高耦合、低内聚时
- 很多系统事件跨越多个不同的处理过程
- 概念上容易理解和构建
其命名习惯: Handler 、 CoOrdinator、Session
优点
- 容易适应UI层的变化
- 领域层代码易于重用(因为UI层一般与应用关系密切)
- 有助于保证应用所需要的操作顺序
- 可以对系统的状态进行推理(UI层不保存系统状态)
臃肿控制器的解决方法
当一个控制器处理了大部分系统事件时,控制器掌握了太多的系统信息,就会形成臃肿的控制器,导致低内聚。解决方法是:
- 增加更多的控制器
- 采用会话控制器替换外观控制器
- 控制器委托任务给别的对象,而不是自己做
- 高内聚的理念
高内聚 High Cohesion
问题
如何使对象功能专注、可理解、可管理,同时又支持低耦合。
解决办法
分配职责时保证高内聚。
用法
- 用作评价工具
- 更多的是一种理念,没有具体的可操作原则。
衡量概念之间相关度的两个指标
- Cohension,内聚:模块内元素之间联系紧密的程度,例如,一个类内部的操作之间。
- Coupling,耦合:两个模块之间联系的强度。
内聚的最佳实践
1 一个类完成的功能不要太多,且这些功能都是同级别的。例如:教授的主要功能是教学,研究员的主要工作是科研。
2 如果同类别的工作太多,则会定义新的类分担任务,相互间合作。
例如:”不是一家人,不进一家门”,“人”指的是操作,职责,”门”指的是模块,类。
类低内聚
- 症状
- 做了太多相互无关的工作:不是你的职责你做了。
- 做了太多工作:是你的职责,但做的事情太多了,需要把职责在细分。
- 原因
- 大粒度的抽象:如打扫卫生可以分为扫地,擦黑板等。
- 做了太多本应该委托给其他类去做的工作。
- 缺点
- 难以理解:因为职责太多,太复杂。
- 难以重用:耦合度太高。
- 难以维护:很难修改。
- 没有稳定的时刻,总是在修改 (通常都会高耦合)。
多态 Polymorphism
问题
如何处理因类型不同而导致行为不同的一类需求?
解决办法
使用多态操作为依据类型变化的行为来分配职责。
推论
- 不要测试对象的类型或条件逻辑,并以此选择相应的行为。
- 即,不要使用条件逻辑,而是为不同的类定义相同名字的方法。
- 不同的类实现相同的接口,或有一个共同的父类(继承)。
纯虚构 Pure Fabrication
问题
依据一些原则(比如,信息专家)获得的解决方案不合适的情况下,既不想违反低耦合、高内聚,也不想违反其他的原则,如何把职责分配给对象?
解决办法
把高度内聚的职责分配给虚构出来的一个类,这个类在领域模型里没有对应的概念。
推论
这种方式在有的场合能起到支持低耦合、高内聚、重用的效果。
原则
- 使用虚构类仍然保持低耦合、高内聚,但可重用性要增加。
- 多数情况下是按照功能来定义新的类,是一种“功能为中心”的对象,如果功能相关性比较高,则满足高内聚的特性。
风险
宽泛地说,虚构对象分为两类,代表性概念为主的分解和行为性概念为主的分解,可能导致面向功能或者面向过程的分析/设计,然后用OO语言去实现。
间接 Indirection
问题
若两个对象直接连接,导致耦合太紧,如何解决?
即,把职责分配到哪里可以避免两个或多个对象之间的直接耦合?如何解耦对象以保持较高的可重用性?
解决办法
把职责分配给一个中介对象,隔离对象,使两个对象、构件或服务之间不产生直接耦合。
因为中介对象有一种特殊的作用,一般对象与中间对象之间直接耦合,相对比较简单。
与纯虚构类似,但目的不同。
隔离变化
问题
如何设计对象、系统和子系统,使得这些成分里面的变化因素、不稳定因素不会对系统的其余部分造成意想不到的影响?
即,需求一定会变化的!如何做到以系统的局部变化为代价就可以应对这一点?
解决办法
标识出能够已知或预计的变化点或者不稳定点,职责分配的时候创建一个稳定的接口,把它们与系统的其余部分隔离开来。
注意:“隔离可能的变化”是一个设计原则,如下技巧都使用隔离变化:数据封装、多态、数据驱动设计、 服务查询、配置文件、接口等都是这种机制的不同体现。
变化点的分类
- 变化点:当前系统已经存在。
- 演化点:当前系统不存在,未来可能存在的变化。
GRASP原则是一种理念,要时刻牢记,随时使用,就会造成潜移默化地加深理解,从而得到更好的设计!
相关文章:
GRASP设计原则
GRASP设计原则介绍9种基本原则创建者 Creator问题解决方法何时不使用?好处信息专家 Information Expert问题解决方法信息怎么做优点低耦合 Low Coupling耦合问题解决方法原则何时不使用?控制器 Controller问题解决方法外观控制器会话控制器优点臃肿控制器的解决方法高内聚 Hi…...
再遇周杰伦隐私协议
本隐私信息保护政策版本:2021 V1 一、重要提示 请您(以下亦称“用户”)在使用本平台App时仔细阅读本协议之全部条款,并确认您已完全理解本协议之规定,尤其是涉及您的重大权益及义务的加粗或划线条款。如您对协议有任…...

关于项目上的一些小操作记录
一 如何在项目的readme.md文件中插入图片说明 1 准备一张图片命名为test.png 2 在maven项目的resources目录下新建文件夹picture,将图片放入该目录下 3 在readme.md文件中期望插入图片的地方编辑如下:  此时&#…...
sql查询不以某些指定字符开头(正则表达式)
我们用到的最多的是:查询以特定字符或字符串开头的记录 字符^用来匹配以特定字符或字符串开头的记录。 例 1 在 tb_students_info 表中,查询 name 字段以“J”开头的记录,SQL 语句和执行过程如下。 mysql> SELECT * FROM tb_students_…...

35.网络结构与模型压缩、加速-2
35.1 Depthwise separable convolution Depthwise separable convolution是由depthwise conv和pointwise conv构成depthwise conv(DW)有效减少参数数量并提升运算速度 但是由于每个feature map只被一个卷积核卷积,因此经过DW输出的feature map不能只包含输入特征图的全部信息,…...

FreeSWITCH跨NAT部署配置详解
本文仅讨论FreeSWITCH部署在NAT之后(里面)这种场景,假设私网地址与公网地址有一个确定的映射关系。这里只涉及mod_sofia(SIP信令及媒体)相关配置,其他模块不在本文讨论之列。配置mod_sofia默认提供两个prof…...

【精选论文 | Capon算法与MUSIC算法性能的比较与分析】
本文编辑:调皮哥的小助理 【正文】 首先说结论: 当信噪比(SNR)足够大时,Capon算法和MUSIC算法的空间谱非常相似,因此在SNR比较大时它们的性能几乎一样,当不同信号源的入射角度比较接近时&…...

卫星、无人机平台的多光谱数据在地质、土壤调查和农业等需要用什么?
近年来,Python编程语言受到越来越多科研人员的喜爱,在多个编程语言排行榜中持续夺冠。同时,伴随着深度学习的快速发展,人工智能技术在各个领域中的应用越来越广泛。机器学习是人工智能的基础,因此,掌握常用…...

30个题型+代码(冲刺2023蓝桥杯)
愿意的可以跟我一起刷,每个类型做1~5题 ,4月前还可以回来系统复习 2月13日 ~ 3月28日,一共32天 一个月时间,0基础省三 --> 省二;基础好点的,省二 --> 省一 目录 🌼前言 🌼…...

快速且有效减小代码包的方法
前言当我们在发布一些APP或者小程序等比较小的程序时候,常常会对其主包大小进行一定的规定,若超过推荐的主包大小则性能会被大大影响,或者再严重一点就不给你过审。如微信小程序中也对主包有一定的大小要求。对此一些比较复杂的小程序就需要考…...

基于matlab评估星载合成孔径雷达性能
一、前言本示例展示了如何评估星载合成孔径雷达 (SAR) 的性能,并将理论极限与 SAR 系统的可实现要求进行比较。SAR利用雷达天线在目标区域上的运动来提供更精细的方位角分辨率。给定雷达的主要参数(例如工作频率、天线尺寸和带宽&…...

Linux_基本指令
新的专栏Linux入门来啦!欢迎各位大佬补充指正!! Linux_基本指令导入文件绝对路径与相对路径隐藏的文件指令ls查看stat查看文件属性cd进入路径mkdir创建目录touch创建文件rm删除man查询手册cp复制mv移动cat查看文件morelessheadtail时间相关的…...

Keras深度学习实战——使用深度Q学习进行SpaceInvaders游戏
Keras深度学习实战——使用深度Q学习进行SpaceInvaders游戏 0. 前言1. 问题与模型分析2. 使用深度 Q 学习进行 SpaceInvaders 游戏相关链接0. 前言 在《深度Q学习算法详解》一节中,我们使用了深度 Q 学习来进行 Cart-Pole 游戏。在本节中,我们将利用深度Q学习来玩“太空侵略…...

从事架构师岗位快2年了,聊一聊我对架构的一些感受和看法
从事架构师岗位快2年了,聊一聊我和ChatGPT对架构的一些感受和看法 职位不分高低,但求每天都能有新的进步,永远向着更高的目标前进。 文章目录踏上新的征程架构是什么?架构师到底是干什么的?你的终极目标又是什么&#…...

零基础机器学习做游戏辅助第十二课--原神自动钓鱼(二)
一、模拟训练环境 上节课我们已经能够判断人物的钓鱼状态,接下来我们就需要对鱼儿上钩后的那个受力框进行DQN训练。 方案有两个: 使用卷积神经网络直接输入图像对网络进行训练。使用普通网络,自己写代码模拟出图像中三个点的动态并把值给神经网络进行训练。这里我们选用第二…...

MapReduce paper(2004)-阅读笔记
文章目录前言摘要(Abstract)一、引言( Introduction)二、编程模型(Programming Model)三、实现(Implementation)3.1、执行概述(Execution Overview)3.2、主节点数据结构(Master Data…...

【蒸滴C】C语言指针入门很难?看这一篇就够了
目录 一、前言 二、指针是什么 小结: 三、指针变量是什么 小结: 四、指针在32位机器和64位机器中的差别 32位机器: 64位机器: 小结: 五、指针和指针类型 (1)指针的意义 (2ÿ…...
C++11新的类功能
文章首发公众号:iDoitnow 1. 特殊的成员函数 C11在原有的4个特殊成员函数(默认构造函数、复制构造函数、复制赋值运算符和析构函数)的基础上新增了移动构造函数和移动赋值运算符。这些特殊成员函数在各种情况下是会通过编译器自动提供的。 …...

Laravel创建定时任务
创建一个任务,创建成功后会在App/Console/Commands中生成一个以Test命名的文件,我们可以在这里面写我们的任务指令。 php artisan make:command Test 运行这个定时任务 run 是运行一次,我们可以用来测试是否成功,work是一直运行&a…...
SaveInstanceState
1. 保存与读取当前状态,MainActivity.java public class MainActivity extends AppCompatActivity {private String TAG "MyLog";TextView textView;Button button;Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedI…...
QMC5883L的驱动
简介 本篇文章的代码已经上传到了github上面,开源代码 作为一个电子罗盘模块,我们可以通过I2C从中获取偏航角yaw,相对于六轴陀螺仪的yaw,qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...

大型活动交通拥堵治理的视觉算法应用
大型活动下智慧交通的视觉分析应用 一、背景与挑战 大型活动(如演唱会、马拉松赛事、高考中考等)期间,城市交通面临瞬时人流车流激增、传统摄像头模糊、交通拥堵识别滞后等问题。以演唱会为例,暖城商圈曾因观众集中离场导致周边…...
《Playwright:微软的自动化测试工具详解》
Playwright 简介:声明内容来自网络,将内容拼接整理出来的文档 Playwright 是微软开发的自动化测试工具,支持 Chrome、Firefox、Safari 等主流浏览器,提供多语言 API(Python、JavaScript、Java、.NET)。它的特点包括&a…...

理解 MCP 工作流:使用 Ollama 和 LangChain 构建本地 MCP 客户端
🌟 什么是 MCP? 模型控制协议 (MCP) 是一种创新的协议,旨在无缝连接 AI 模型与应用程序。 MCP 是一个开源协议,它标准化了我们的 LLM 应用程序连接所需工具和数据源并与之协作的方式。 可以把它想象成你的 AI 模型 和想要使用它…...

(二)原型模式
原型的功能是将一个已经存在的对象作为源目标,其余对象都是通过这个源目标创建。发挥复制的作用就是原型模式的核心思想。 一、源型模式的定义 原型模式是指第二次创建对象可以通过复制已经存在的原型对象来实现,忽略对象创建过程中的其它细节。 📌 核心特点: 避免重复初…...
python爬虫:Newspaper3k 的详细使用(好用的新闻网站文章抓取和解析的Python库)
更多内容请见: 爬虫和逆向教程-专栏介绍和目录 文章目录 一、Newspaper3k 概述1.1 Newspaper3k 介绍1.2 主要功能1.3 典型应用场景1.4 安装二、基本用法2.2 提取单篇文章的内容2.2 处理多篇文档三、高级选项3.1 自定义配置3.2 分析文章情感四、实战案例4.1 构建新闻摘要聚合器…...

Psychopy音频的使用
Psychopy音频的使用 本文主要解决以下问题: 指定音频引擎与设备;播放音频文件 本文所使用的环境: Python3.10 numpy2.2.6 psychopy2025.1.1 psychtoolbox3.0.19.14 一、音频配置 Psychopy文档链接为Sound - for audio playback — Psy…...
vue3 定时器-定义全局方法 vue+ts
1.创建ts文件 路径:src/utils/timer.ts 完整代码: import { onUnmounted } from vuetype TimerCallback (...args: any[]) > voidexport function useGlobalTimer() {const timers: Map<number, NodeJS.Timeout> new Map()// 创建定时器con…...

uniapp微信小程序视频实时流+pc端预览方案
方案类型技术实现是否免费优点缺点适用场景延迟范围开发复杂度WebSocket图片帧定时拍照Base64传输✅ 完全免费无需服务器 纯前端实现高延迟高流量 帧率极低个人demo测试 超低频监控500ms-2s⭐⭐RTMP推流TRTC/即构SDK推流❌ 付费方案 (部分有免费额度&#x…...
【HTTP三个基础问题】
面试官您好!HTTP是超文本传输协议,是互联网上客户端和服务器之间传输超文本数据(比如文字、图片、音频、视频等)的核心协议,当前互联网应用最广泛的版本是HTTP1.1,它基于经典的C/S模型,也就是客…...