零雨其蒙《UML和模式应用》学习笔记(二)
(零雨其蒙原创 转载请注明)
2007 年 3 月 4 日星期日
第 17 章 GRASP :基于职责设计对象
P197 最关键的软件开发工具是受过良好设计原则训练的思维, 而不是 UML 或任何其他技术。
P197 总架构师利用 UML 包图 提出大型逻辑架构的构思。
开始设计需要输入的制品
(这些制品都是分析阶段的产物)
用例文本 定义最终必须得到软件对象的支持(对象必须能够实现实例)的可视行为。在 UP 中,这种 OO 设计也被顺理成章地称为用例实现。 |
补充规格说明 定义了非功能性的目标,例如国际化,我们的对象必须满足这些目标。 |
系统顺序图( SSD ) 确定系统操作信息,它是合作对象交互图中的开始消息。 |
词汇表 明确来自 UI 层的参数或数据、传递到数据库的数据细节,以及详细的特定项逻辑或验证需求,如合法的格式和对产品 UPC (童用产品代码)的有效性验证。 |
操作契约 用来补充用例文本,以明确在系统操作中软件对象必须完成什么任务。后置条件定义了系统操作的详细结果 |
领域模型 描述了软件架构的领域层软件领域对象的名称和属性 |
通过用例文本描述需求, 用例就是需求,主要是说明系统如何工作的功能性或行为性需求。( P48 )而 SSD ,操作契约和词汇表是对用例中的功能或行为需求的细化和补充,其中操作契约是对 SSD 中的操作的详细描述;补充规格说明则是对整个需求分析过程中用例未能描述的非功能目标的补充。 SSD 会帮助 DCD 过程交互图的绘制,领域模型则会启发领域层软件领域对象的名称和属性的设计。
RDD
P198 OO 设计建模的总的来说,基于职责驱动设计( RDD )所代表的内在含义是考虑怎样给协作中对象分配职责。
P200
RDD 是一种隐喻 RDD 是思考 OO 软件设计的一般性隐喻。把软件对象想象成具有某种职责的人,他要与其他人协作以完成工作。 RDD 使我们把 OO 设计看作是 有职责对象进行协作 的共同体。 |
职责和职责驱动设计
思考软件对象设计以及大型构件的流行方式是,考虑其职责、角色和协作。这是被称为职责驱动设计 [WM02] 大型方法的一部分。
软件对象的职责,即对其所作所为的抽象。 UML 把职责定义为“类元的契约和义务” [OMG03b] 。就对象的角色而言,职责与对象的义务和行为相关。职责分为以下两种类型: 行为 和 认知 。
对象的行为职责包括:
l 自身执行一些行为,如创建对象或计算。
l 初始化其他对象中的动作
l 控制和协调其他对象中的活动
对象的认知职责包括:
l 对私有封装数据的认知
l 对相关对象的认知
l 对其能够导出或计算的事物的认识
在对象设计中,职责分配给对象类。 例如,我可以声明“ Sale 负责创建 SalesLineItems ”(行为职责 1 ),或“ Sale 负责认知其总额”(认知职责 3 )
职责与方法
职责与方法并非同一事物。 职责是一种抽象,而方法实现了职责。
职责借助于方法来实现,该方法既可以单独动作,也可以与其他方法和对象协作。
GRASP 与 RDD
GRASP ( General Responsibility Assignment Software Patterns 通用职责分配软件模式)对一些基本的职责分配原则进行了命名和描述,因此掌握这些原则有助于支持 RDD 。
2007 年 3 月 5 日星期一
GRASP 模式
Creator 创建者
名称:创建者
问题:谁创建了 A ?
解决方案:如果以下条件之一为真时(越多越好),将创建类 A 的实例的职责分配给类 B (也就是 B 创建 A , B 应该和 A 有哪些关系或 B 应该具有哪些特征):
l B “包含”(比如 Board (棋盘)“包含” Square (棋盘上的方格))或组成聚集(更准确的说法是组成聚合,也称组合)了 A
l B 记录 A
l B 紧密地使用 A
l B 具有 A 的初始化数据
或许可以说, B 依赖 A ,则 B 要创建 A 。
Information Expert 信息专家
名称:信息专家
问题:给对象分配职责的基本原则是什么?
解决方案:把职责 分配 给具有完成该职责所需信息的那个类。
职责需要履行职责的信息,即关于其他对象的信息、对象自身的状态、对象周围的环境、对象能够导出的信息,等等。
或许可以说,类的属性(信息,认知)决定了类的方法(职责,行为),但从领域模型而来的设计模型(软件中的类或接口或包)应该已经具备了这样的特点。
Low Coupling 低耦合
名称:低耦合
问题:如何减少因变化产生的影响?
解决方案:分配职责以使(不必要的)耦合保持在较低的水平。用该原则对可选方案进行评估。
或许可以说,低耦合是遵循信息专家原则的结果,也是设计对象的目标
P248 内部或自身较高的偶合度不是问题,反之与不稳定 (可能该元素今天有明天就没有了,它不是必要元素)的元素的耦合才是真正的问题所在。
Controller 控制器
在一些 OOA/D 方法中, 控制器 是对应用逻辑对象的命名,它接收请求并“控制”(协调)对请求的处理。
名称:控制器
问题:在 UI 层之上,首先接收和协调(“控制”)系统操作的对象是什么?
解决方案:把职责分配给能代表下列选择之一的对象(两类控制器):
l 代表全部“系统”、“根对象”、运行软件的设备或主要的子系统(这些是外观控制器( façade controller )的所有变体)。(这种控制器是领域对象)
l 代表发生系统操作的用例场景(用例或会话控制器( session controller ,其例子或许是 EJB 的 Session Bean ))。 P221 如果你选择用例控制器,那么对于每个用例,应用使用不同的控制器。这种控制器不是领域对象,它是支持系统的人工构造物(在 GRASP 模式的术语里是纯虚构( Pure Fabrication ))
我的理解是,从广义上来讲,控制器是连接 UI 和领域对象的纽带,与所熟悉的应用(比如 MVC 中的 c )所表现出来的用处一样,对来自于 UI 层的消息进行接收和控制(分配( 委派 ),调度(协调)等)。然而狭义一点说,按照 Larman 的说法, MVC 中的 C 与 GRASP 中的 C 并非一物,前者是 UI 层的一部分,并且控制 UI 层的交互及页面流。后者则是领域层的一部分,它控制或协调工作请求的处理,它根本不知道所用的 UI 技术(如 Web UI , Swing UI ,……)是什么。( P222 ) 然而根据系统操作的定义,和控制器模式的作用,我依然觉得 GRASP 控制器模式和 Struts 中的 Controller 是同一物,只不过 Larman 将其归在了领域层,或者可以这样理解, MVC 中的控制器是 GRASP 控制器模式的特例,原因是其系统操作只包括处理 Web 页面的输入、点击等事件。
P221 控制器模式的重要结果是, UI 对象(例如,窗口或按钮对象)和 UI 层不应具有实现系统事件的职责。换句话说, 系统操作 应当在对象的应用逻辑层或领域层进行处理,而不是在系统的 UI 层处理。
High Cohesion 高内聚
名称:高内聚
问题:怎样使对象保持有内聚、可理解和可管理,同时具有支持低耦合的附加作用?
解决方案:职责分配应保持高内聚,依此来评估备选方案。
我的理解是,内聚的含义是与其内部代码和内部代码的相关度有关的,高内聚表现为内部代码相关度高。