通用职责分配软件模式
General Responsibility Assignment Software Patterns
Understanding responsibilities is key to good object-oriented design.
--Martin Fowler
GRASP 定义了9个基本的OO设计原则或基本设计构件.
There are nine GRASP patterns:
Creator, Controller, Pure Fabrication,
Information Expert, High Cohesion, Indirection,
Low Coupling, Polymorphism, Protected Variations.
One person’s pattern is another person’s building block.
某人的模式是其他人的原始构造模块.
创建者 Creator
解决的问题: 对象应该由谁来创建?
解决方案:
如果以下条件为真时(越多越好), 将创建类A实例的职责分配给B:
· B “包含” 或组成聚集了A
· B 记录A
· B 紧密的适用A
· B 具有A的初始化数据
如果有一个以上的选项适用, 通常首选聚集或包含A的类B
组合聚集部分, 容器容纳内容, 记录者进行记录, 所有这些都是类图中类之间极为常见的关系. 创建者模式建议, 封装的容器或记录器类是创建其所容纳或记录的事务的很好的候选者. 当然这只是一个准则.
禁忌
对象的创建往往有相当的复杂性, 最好的方法是吧创建职责委派给工厂的辅助类,而不是直接使用创建者
信息专家 Information Expert
问题: 给对象分配职责的基本原则是什么?
一个设计模型也许要定义数百或数千个类, 一个应用程序也许需要实现数百或者数千个职责. 在对象设计中, 当定义好对象间的交互后, 我们就可以对类的职责分配作出选择. 如果选择的好, 系统就会易于理解, 维护和扩展, 而我们的选择也能为未来的应用提供更多复用构件的机会.
解决方案: 把职责分配给具有完成该职责所需信息的那个类
职责所需要履行职责的信息,即关于其他对象的信息,对象自身的状态,对象自身周围的环境,对象能够导出的信息,等等. 在本例中, 为了能够检索和表示任何square, 某个对象必须知道所有Square.
专家模式通常导致这样一种设计, 软件对象所做的操作通常是作用与它们在真实世界中所代表的非生命体的那些操作. Peter Coad 称之为 “DIY” 策略. 例如, 在真实世界中, 不借助电子装置的帮助, 销售本身无法告诉你它的总额, 销售是一种非生命体, 销售的总额是人算出来的. 但是在面向对象的软件领域, 所有对象都是”活的” 或者 “有生命的”, 并且它们可以承担职责, 完成任务. 从根本上说, 它们只完成那些与它们所知信息有关的事情.
低耦合 Low Coupling
问题: 为什么是这个类去创建而不是其他类?
怎样降低依赖性, 减少变化带来的影响, 提高重用性.
耦合原则适用与软件开发的许多方面, 它实际上是构件软件的最重要的目标之一.
解决方案: 分配职责以使(不必要的) 耦合保持在较低的水平. 用该原则对可选方案进行评估.
我们用低耦合原则来评价现有设计,或者评价在新的可选方案(其他方面都等价的方案)之间作出选择,我们应该首选耦合更低的设计.
在更高的目标层次上考虑, 为什么期望低耦合呢? 换言之, 为什么我们要减少变化产生的影响呢? 因为低耦合往往能够减少修改软件所需的时间, 工作量和缺陷. 这只是个简要的回到,但是它们对于构建和维护软件而言具有重大意义.
简要的说, 耦合(coupling) 是元素与其他元素的连接,感知和依赖的程度的度量. 如果存在耦合或依赖, 那么当被依赖的元素发生变化时, 则依赖者也会受到影响. 例如, 子类和超类是强耦合的. 调用对象B的操作的对象A与对象B的服务之间具有耦合作用.
高耦合的设计, 会遇到以下问题:
l 由于相关类的变化而导致本体的被迫变化
l 难以单独的理解
l 由于使用高耦合类时需要它所依赖的类, 因此很难重用
在实践中, 耦合程度不能脱离专家, 高内聚等其他原则孤立的考虑. 不过, 它的确是改进设计所需要考虑的因素之一.
禁忌
高耦合对于稳定和普遍使用的元素而言并不是问题. 例如, J2EE应用能够安全的将自己与JDK耦合, 因为java库是稳定的, 普遍使用的.
高耦合本身并不是问题所在, 问题是与某些方面不稳定的元素之间的耦合, 这些方面包括接口, 实现等
控制器 Controller
问题: 在UI层之上首先接收和协调(“控制”)系统操作的对象是什么?
解决方案: 把职责分配给能代表下列选择之一的对象:
· 代表全部”系统”, “根对象”, 运行软件的设备或主要的子系统(façade controller的所有变体)
· 代表发生系统操作的用例场景(用例或会话控制器(session controller)), 通常命名为<UseCaseName>Handler, <UseCaseName>Coordinator 或 <UseCaseName>Session.
Option 1: 代表全部”系统” 或 “根对象”
Option 2: 代表运行软件的设备
Option 3: 代表用例或者会话. 如(SomeHandler 或者someSession)
控制器设计的常见缺陷是分配职责过多. 这时, 控制器会低内聚, 从而违反了高内聚原则.
准则: 正常情况下, 控制器应当吧需要完成的工作委派给其他的对象. 控制器只是协调或控制这些活动, 本身并不完成大量工作.
臃肿的控制器
设计不良的控制器内聚性低, 即没有重点, 并且要处理过多领域的职责, 这种控制器叫做臃肿的控制器. 臃肿的迹象有:
l 只有一个控制器类来接收系统中全部的系统事件, 而且有很多系统事件. 如果选择了外观控制器就会碰到这种情况.
l 为了处理系统事件, 由控制器完成诸多必要的任务, 而不是把工作委派出去. 通常就会违反信息专家和高内聚模式.
l 控制器有很多属性, 并且它维护关于系统或领域的重要信息( 这些职责本应分配给其他对象 ), 或者它要复制在其它地方可以找到的信息.
解决控制器臃肿的办法:
l 增加控制器.
l 设计控制器, 使它把完成的每个系统操作的职责委派给其它对象.
再强调一次: 控制器模式的重要推论是, UI对象和UI层不应具有处理系统事件的职责.
高内聚 High Cohesion
从对象设计的角度上说, 内聚(或者更为专业的说, 是功能内聚)是对元素职责的相关性和集中度的度量.
在左侧的方案中, MonopolyGame对象自己完成全部工作, 而在右侧方案中, 它为playGame请求工作进行了委派和协调.
内聚是软件设计中的一种基本品质, 内聚可以非正式的用于度量软件元素操作在功能上的相关程度, 也用于度量软件元素完成的工作量.
有100个方法和2000行源代码的Big对象, 要比只有10个方法和200行代码的Small对象所完成的任务多很多. 如果Big对象的100个方法覆盖了众多不同的职责领域, 那么Big对象比Small对象的功能内聚性更低. 概括的讲, 代码的数量及其相关性都是对象内聚程度的指示器.
很明显, 低内聚不只是意味着对象仅仅依靠本身工作, 实际上, 具有2000行代码的低内聚对象或许需要和大量其他对象进行写作. 下面是一个关键点, 所有的交互也都会产生高耦合. 低内聚和高耦合通常是齐头并进的.
在实践中, 内聚程度不能脱离其它职责及其它原则(如信息专家和低耦合)单独的考虑.
与低耦合一样, 在所有的设计决策期间, 高内聚是要时刻牢记的原则, 它是一个需要不断考虑的基本原则. 它是评估所有设计决策时, 设计者要使用的评价原则.
Grady Booch认为, 当构件元素(如类) “能够共同协作并提供某种良好界定的行为”, 则存在高功能性内聚.
根据经验, 高内聚的类方法数目较少, 功能性有较强的关联, 而且不需要做太多的工作. 如果任务规模较大的华, 它就与其它对象协作, 共同完成这项任务.
高内聚的类优势明显, 因为它易于维护,理解和复用. 高度相关的功能性和少量的操作相结合, 也可以简化维护和改进的工作. 细粒度的, 高度相关的功能性也可以提高复用的潜力.
高内聚模式是真实世界的类比. 显而易见, 如果一个人承担了过多不相关的工作, 特别是本应委派给别人的工作, 那么此人一定没有很高的工作效率. 从某些还没有学会如何分派任务的经理身上可以发现这种情况, 因此正承受着低内聚所带来的困难,变得”分身乏术”.
另一个经典原则: 模块化设计
模块化是将系统分解成一组内聚的, 松散耦合的模块的特性.
不良内聚导致不良耦合, 反之亦然. 我把内聚和耦合称为软件工程中的阴和阳.
因为它们是互相依赖的.
OOD 非魔力地带
在对象设计中, 不需要任何不合道理的决断, 职责的分配和协作的选择都是能够被合理解释和学习的. 事实上, OO设计更接近于科学而非艺术, 尽管存在巨大的创造性和优雅设计的空间.
准则 (guidelines)
在编码时, 至少首先要编写启动初始化的程序. 但是在OO设计建模的过程中, 要最后考虑启动初始化. 知道发现那些是真正需要被创建和初始化的. 然后, 再对初始化进行设计以支持其他用例实现的需要.
当存在多个可选设计时, 应当深入的观察可选设计所存在的内聚和耦合, 以及未来可能存在的进化压力. 选择具有良好内聚,耦合和在未来出现变化时能保持稳定的设计.
命令-查询分离原则(Command-Query Separation Principle)
In particular, the roll method is void. It has no return value. For example:
// style #1; used in the official solution
public void roll()
{
faceValue = // random num generation
}
public int getFaceValue()
{
return faceValue;
}
为什么不将两个方法合并起来, 使roll方法返回新的faceValue呢? 如下所示:
// style #2; why is this poor?
public int roll()
{
faceValue = // random num generation
return faceValue;
你可以发现大量使用风格2 的例子, 但是这种方式并不合适, 因为它违反了命令-查询分离原则(Command-Query Separation Principle), CQS是针对方法的经典OO设计原则. 该原则指出, 任何方法都是如下情况之一:
l 执行动作(更新, 调整, ...)的命令方法, 这种方法通常具有改变对象状态等副作用, 并且是void的(没有返回值).
l 向调用者返回数据的查询, 这种方法没有副作用, 不会永久性的改变任何对象的状态.
关键是, 一个方法不应该同时属于以上两种类型.
Roll()方法是命令, 它具有改变Die对象的faceValue属性状态的副作用. 因此, 它不应该同时返回新的faceValue, 否则该方法也会成为查询, 从而违反了”必须为void”的规则.
CQS被公认为计算机科学理论中最有价值的原则, 因为遵循该原则, 你能够更容易的推测出程序的状态, 在查询状态时不会同时发生变更. 这样使得设计更便于理解和预见. 例如, 如果应用一直遵循CQS, 那么你会知道查询或者getter方法不会做出任何修改, 而命令也不会有任何返回. 这是个简单的模式. 这通常是要严格遵循的, 因为如果突然采取其他方法, 将会产生令人不快的意外, 从而违反软件开发中最小意外(Least Surprise)的原则
可见性
l 属性可见性
l 参数可见性
l 局部可见性
l 全局可见性
第二部分的连接:
通用职责分配软件模式(GRASP)学习笔记(二)
分享到:
相关推荐
GRASP 模式是 General Responsibility Assignment Software Pattern(通用责任分配软件模式)的缩写,这个模式出自《UML 和模式应用》。在建立概念模型时,GRASP 模式可以指导我们如何分配类的职责,解决类之间如何...
GRASP 模式是 General Responsibility Assignment Software Pattern(通用指责分配软件模式)的缩写。它是一种软件设计模式,旨在帮助开发者设计出更加灵活、可维护和可复用的软件系统。 GRASP 模式主要包括九大...
《设计模式学习笔记》主要探讨了GOF的23种设计模式以及类设计的基本原则,旨在帮助开发者理解和应用这些经过时间验证的成熟解决方案。设计模式是面向对象软件设计中的核心概念,它们为解决常见的设计问题提供了标准...
GRASP模式,OO原则和设计模式的基础,原创不易,请珍惜下载
除了上述的经典设计模式外,还有一个非常重要的概念叫做GRASP(General Responsibility Assignment Software Patterns),即通用职责分配软件模式。GRASP包含了九种模式,用于指导对象的设计和职责分配。GRASP模式在...
本课程涵盖了四个核心的GRASP(通用职责分配系统)模式:多态(Polymorphism)、纯虚构(Pure Fabrication)、间接性(Indirection)和防止变异(Protected Variations)。 **多态(Polymorphism)** 多态是面向...
在软件设计中,GRASP(General Responsibility Assignment Software Patterns,通用职责分配软件模式)是一组指导原则,用于帮助开发者创建高质量、可复用和可维护的软件。这些原则旨在提高软件的内聚性和降低耦合度...
GRASP原则是指导如何合理分配对象职责的一组原则,有助于提高代码的可读性和可维护性。 1. **控制器(Controller)**: 处理用户输入,协调对象间的交互,降低系统的复杂性。 2. **主体(Prime Creator)**: ...
本书特别强调了GRASP(通用职责分配软件模式)这一面向对象设计的典型模式。 GRASP 模式是一组面向对象设计原则,它帮助开发者决定在软件设计中如何合理地分配和分配职责给对象。GRASP 包括诸如信息专家、创建者、...
GRASP10是一款专业的天线仿真软件,广泛应用于天线设计与分析领域。其全称为Geometrical Theory of Diffraction and Physical Optics Simulation Program,意为几何绕射理论和物理光学仿真程序。GRASP软件基于高频...
GRASP(General Responsibility Assignment Software Patterns)是一种对象设计模式,用于将责任分配给软件对象。GRASP模式提供了一些基本原则和策略,指导开发人员在设计对象时分配责任和确定对象之间的关系。 在...
GRASP(General Responsibility Assignment Software Patterns)是一套面向对象设计的原则,用于指导软件开发中的职责分配。这个概念在软件工程中至关重要,特别是在UML(统一建模语言)和软件建模中,因为它帮助...
3. GRASP模式:GRASP(通用职责分配软件模式)是一种面向对象设计模式,它帮助开发人员在设计系统时分配职责给对象。这些模式提供了一组设计原则,用以指导开发人员如何构建出具有良好结构的软件系统,使得系统易于...
这一步骤通常在GIS软件中完成,如ArcView,生成高分辨率的地图,展示物种的潜在分布模式。 4. **结果验证与优化**:通过将预测结果与实际观测数据比较,验证模型的准确性。如果有必要,可以通过调整模型参数或增加...
【管家婆GRASP 7.1 完美版本】是一款针对中小型企业设计的全面企业管理软件,旨在帮助企业高效管理财务、进销存、生产等业务环节。这款软件以其稳定性、易用性和功能全面性赢得了广大用户的青睐。在描述中提到的问题...
### 设计模式实践-软件开发 #### 模式概念与应用背景 在软件工程领域,设计模式被视为一种解决常见问题的有效方法。正如烹饪时需要遵循菜谱...因此,深入学习和掌握设计模式对于每一位软件开发者而言都是非常必要的。
总之,GRASP作为面向对象设计的一个关键工具,能够帮助开发者在软件需求分析阶段更有效地构建对象模型,明确对象职责,优化系统结构,提升代码质量。通过理解和应用GRASP原则,开发者可以创建出更稳定、可维护和易于...
这就是GRASP(通用职责分配软件模式)的作用。GRASP包含了9种模式,它们定义了对象设计和职责分配的基本原则,为如何将现实世界问题抽象为对象提供指导。 1. **信息专家(Information Expert)**:这是面向对象设计...