grasp: 设计带职责的对象
DESCRIPTION
GRASP: 设计带职责的对象. 徐迎晓 [email protected] 复旦大学软件学院. 设计带职责的对象. 交互设计和职责分配的质量决定系统的质量 可维护性 可理解性 可重用性 可扩展性 好的面向对象设计原则可用于交互图设计和职责分配 — GRASP 模 式. GRASP :通用职责分配软件模式 General Responsibility Assignment Software Patterns 将职责分配给对象的基本原则. GRASP: 设计带职责的对象. 五个 GRASP 模式 应用 G RASP 实现 Process Sale 用例 - PowerPoint PPT PresentationTRANSCRIPT
设计带职责的对象交互设计和职责分配的质量决定系统的质量可维护性可理解性可重用性可扩展性
好的面向对象设计原则可用于交互图设计和职责分配— GRASP 模式
GRASP :通用职责分配软件模式 General Responsibility Assignment
Software Patterns
将职责分配给对象的基本原则
GRASP: 设计带职责的对象
五个 GRASP 模式应用 GRASP 实现 Process Sale 用例可见性设计类图设计
五个 GRASP 模式
. Low Coupling
. High Cohesion
. Controller
. Creator
. Information Expert
模式: Low Coupling
Problem :如何降低依赖、减少改变的影响,增加重用性 ?
Solution: 分配职责时使耦合低
原理:耦合表明两个类之间连接的强度,一个类是
否依靠其他类A 具有低耦合,则 A 不依赖很多其他的类
高耦合带来的问题其他类改变则可能自己也必须改变单独(无其他类时)难以理解由于需要很多其他类,难以重用
举例 we have a need to create a Payment instance and associate it with the Sale.
谁来创建 Payment 实例 ?
两种都假定 Sale 和 Payment 之间有关联, register 创建则增加关联,不好
讨论
低藕合模式常与专家、高内聚一起使用是基本目标,所有设计决策中都要考虑中等层度的藕合是正常和必需的(对象之间需要连接以便协作)优点:不受其他组件变化的影响,易于理解,易于重用
类 X 和类 Y 之间常见的藕合X 有属性引用 Y 的实例X 对象调用 Y 对象的服务X 的方法引用 Y 的实例(参数,局部变量,
返回值 )X 是 Y 直接或间接子类Y 是接口, X 实现 Y
But 对稳定元素的藕合和普遍的元素藕合很少会有问题如类库
五个 GRASP 模式
. Low Coupling
. High Cohesion
. Controller
. Creator
. Information Expert
模式: Hign Cohesion
Problem: 如何使复杂性可管理 ?
Solution: 分配职责时使内聚度高
内聚:类的职责如何紧密关联类或子系统等若职责紧密关联,且没有大量
的工作,则具有高内聚度高内聚则方法的数量相对较少若 task is large, 则与其他对象协作低内聚说明类做了很多无关的事情,或做了
太多的事情低内聚的问题:难以理解,重用,维护,易
受变化的影响
不独立使用,而是与专家、低藕合模式一起使用评估所有设计决策的一个准则
Register 做很多系统操作,下图哪个好?
RDB-RPC-Interface class responsible for interacting with relational
databases and for handling remote procedure calls
(two vastly different functional areas)
RDBInterface classcompletely responsible for interacting with
relational databases.hundreds or thousands of methods(all
related)A lot of supporting code
RDBInterface classOnly partially responsible for interacting
with relational databases interacts with a dozen other classes
related to RDB access
Company classcompletely responsible for (a) knowing its
employees and (b) knowing its financial information.
total number of public methods is small the amount of supporting code is small
可低内聚的场合
grouping of responsibilities or code into one class or component to simplify maintenance by one person只有 1 , 2 个 SQL 专家,对 OO 不熟
software architect may decide to group all the SQL statements into one class, RDBOperations
可低内聚的场合 2distributed server objects less remote calls, and better performance.
远程服务器对象要 fewer and larger, less cohesive ,为很多操作提供接口
远程操作粗粒度,以便一次 remote operation call 可以做或请求更多的工作
Example 1: remote object with three fine-grained operations setName, setSalary, and setHireDate
Example 2: one remote operation setData which receives a set of data
Which is better?
五个 GRASP 模式
. Low Coupling
. High Cohesion
. Controller
. Creator
. Information Expert
模式 :Controller
Problem: 谁负责处理系统输入事件 ?
Solution: 将处理系统输入事件的职责分配给代表以下的类: 代表整个系统、设备或子系统 - 外观
Controller ( facade controller ) 代表整个业务过程或组织( facade controller ) 代表现实世界中可能执行该任务的角色 (role
controller) 代表系统事件发生的用例场景, (use-case or
session controller)
Problem:The UI & domain layers should be loosely
coupledWhich object should coordinate msgs
between the UI and other domain objects?Solution (advice):
Assign responsibility to an object representing..
The ‘system’ or a ‘root’ object (Store, Bank) A device/subsystem (AccountingSystem,
BankATM) A use case scenario (GameHandler) ‘Single channel of communication between layers’
“window,” “applet,” “widget,” “view,” and “document” 不是控制器,而是将事件发往控制器系统操作在设计时通常交给控制器
可供选择的代表整个系统、设备或子系统
Register, POSSystem代表整个业务过程或组织
Store代表现实世界中可能执行该任务的角色
Cashier代表系统事件发生的用例场景
ProcessSaleHandler
整个系统、设备或子系统
系统事件发生的用例场景
讨论
大多数系统接受外部输入事件 (GUI,传感器信号 ,…)
一个用例中所有系统事件用一个控制器处理,不同用例用不同控制器控制器通常将将需要做的工作委托给其他对象,自己并不做很多工作
优点业务处理由业务对象完成,而不是把图形界
面作为控制器,这样可重用性高将控制器的职责委托给各个领域类,支持逻辑重用但要防止控制器过于臃肿可用多个控制器可用角色控制器或用例控制器,而不是
facade controller
图形界面
不好的做法
五个 GRASP 模式
. Low Coupling
. High Cohesion
. Controller
. Creator
. Information Expert
模式: CreatorProblem: 谁负责创建新的对象 ?
Solution: 如果满足以下条件之一,则将创建类 A 的实例的职责分配给
类 B B 聚合 A 对象 B包含 A 对象 B contains A objects. B记录 A 对象 (前三个最常用 ) B 紧密使用 A 对象 B 具有创建 A 对象时需要传入的初始化数据
B 是 A 的 Creator 如果有多个类满足条件,优先选择聚合或包含关系
Name: Creator Problem: Who creates an A? Solution: (this can be viewed as advice) Assign class B the responsibility to create an instance of class A if one of these is true (the more the better):
B "contains" or compositely aggregates A.
B records A.
B closely uses A.
B has the initializing data for A.
举例
谁负责创建 SalesLineltem 对象 ?
讨论低耦合 对依赖的维护少 可重用性高简明,封装But 若出于性能考虑使用回收的实例,或根据外部的值从一组类似的类中挑选一个创建实例 建议将创建工作交给 helper class----Factory ,而
不使用本模式
五个 GRASP 模式
. Low Coupling
. High Cohesion
. Controller
. Creator
. Information Expert
模式: Information Expert
Problem OOD 中分配职责最基本的原则是什么 ?
Solution 将职责分配给 Information Expert (拥有完成该职责所需要信息的类)
1. 如果设计模型存在相关的类,则到领域模型中查找2. 否则,查看领域模型,应用或扩展领域模型得到相应的设计类
画交互图时碰到的问题:计算总价 ( 总计, grand total )的职责分配给谁 ? 检查领域模型或设计模型
计算总价需 要知道所 有销售条目( SalesLineltem )及其各个条目的总价( subtotals )之和Sale包含 SalesLineltem这些信息——所以计算总价( grand total )的职责分配给Sale。
此时对交互图和类图可以增加哪些内容 ?
各个条目 的总价( subtotals. ) 分 配 给谁 ?需要知道数量 SalesLineltem.quantity 和单价
ProductSpecification.price
分配给 SalesLineltem
交互图和类图增加什么内容 ?
获取单价的职责分配给谁 ?
ProductSpecification包含该信息
最终通过 Information Expert 模式得到的职责分配为了能得到总价的信息:
最终通过 Information Expert 模式得到的协作图
讨论模式 Information Expert
来自直觉 -- 对象做的事情总是与其拥有的信息有关常需要多个对象协作
But 影响耦合和内聚时,可能不使用Expert将销售保存的数据库的职责分配给谁 ?
优点
低耦合 -- 对象用自己的信息,封装性好高内聚 - 行为分布在具有所需信息的类上,易于理解和维护
GRASP: 设计带职责的对象
五个 GRASP 模式应用 GRASP 实现 Process Sale 用例可见性设计类图设计
应用 GRASP 实现 Process Sale 用例
enterItem(itemID, quantity)
:System: Cashier
endSale
makePayment(amount)
a UML loop interaction frame, with a boolean guard expression
external actor to system
Process Sale Scenario
system as black box
the name could be "NextGenPOS" but "System" keeps it simple
the ":" and underline imply an instance, and are explained in a later chapter on sequence diagram notation in the UML
a message with parameters
it is an abstraction representing the system event of entering the payment data by some mechanism
description, total
return value(s) associated with the previous message
an abstraction that ignores presentation and medium
the return line is optional if nothing is returned
total with taxes
change due, receipt
makeNewSale
[ more items ]loop
先为每个系统操作创建独立的图,将每个系统事件作为起始消息若图太复杂,分解成小的图使用系统操作合约和用例描述作为起点,使用 GRASP 等模式
Controller
协作图:每个系统事件要画一个
顺序图:可在一张图上
太长的也可每个系统事件 分开
enterItem(itemID, quantity)
:System: Cashier
endSale
makePayment(amount)
a UML loop interaction frame, with a boolean guard expression
external actor to system
Process Sale Scenario
system as black box
the name could be "NextGenPOS" but "System" keeps it simple
the ":" and underline imply an instance, and are explained in a later chapter on sequence diagram notation in the UML
a message with parameters
it is an abstraction representing the system event of entering the payment data by some mechanism
description, total
return value(s) associated with the previous message
an abstraction that ignores presentation and medium
the return line is optional if nothing is returned
total with taxes
change due, receipt
makeNewSale
[ more items ]loop
makeNewSale
:Register
makeNewSale
:Salecreate
Register creates a Sale by Creator
create lineItems :List<SalesLineItem>
by Creator, Sale creates an empty collection (such as a List) which will eventually hold SalesLineItem instances
by Creator and Controller
this execution specification is implied to be within the constructor of the Sale instance
enterItem(itemID, quantity)
:System: Cashier
endSale
makePayment(amount)
a UML loop interaction frame, with a boolean guard expression
external actor to system
Process Sale Scenario
system as black box
the name could be "NextGenPOS" but "System" keeps it simple
the ":" and underline imply an instance, and are explained in a later chapter on sequence diagram notation in the UML
a message with parameters
it is an abstraction representing the system event of entering the payment data by some mechanism
description, total
return value(s) associated with the previous message
an abstraction that ignores presentation and medium
the return line is optional if nothing is returned
total with taxes
change due, receipt
makeNewSale
[ more items ]loop
enterItem
UC3. Cashier enters item identifier.4. System records sale line item and presents item description, price, and running total.
2: makeLineItem(desc, qty)enterItem(id, qty)
1: desc = getProductDesc(id) 2.1: create(desc, qty)
1.1: desc = get(id)
:Register :Sale
:ProductCatalog
sl: SalesLineItem
lineItems : List<SalesLineItem>
: Map<ProductDescription>
2.2: add(sl)
by Expert
by Controllerby Creator
add the newly created SalesLineItem instance to the List
enterItem(itemID, quantity)
:System: Cashier
endSale
makePayment(amount)
a UML loop interaction frame, with a boolean guard expression
external actor to system
Process Sale Scenario
system as black box
the name could be "NextGenPOS" but "System" keeps it simple
the ":" and underline imply an instance, and are explained in a later chapter on sequence diagram notation in the UML
a message with parameters
it is an abstraction representing the system event of entering the payment data by some mechanism
description, total
return value(s) associated with the previous message
an abstraction that ignores presentation and medium
the return line is optional if nothing is returned
total with taxes
change due, receipt
makeNewSale
[ more items ]loop
endSale
Cashier repeats steps 3-4 until indicates done. 指示重复5. System presents total with taxes calculated.
endSale
:RegisterendSale( s :Sale1: becomeComplete
by Expertby Controller
:Saletot = getTotal 1 *[ i = 1..n]: st = getSubtotal
:ProductDescription
1.1: pr = getPrice
lineItems[ i ] :SalesLineItem
«method»public void getTotal(){ int tot = 0; for each SalesLineItem, sli tot = tot + sli.getSubtotal(); return tot}
enterItem(itemID, quantity)
:System: Cashier
endSale
makePayment(amount)
a UML loop interaction frame, with a boolean guard expression
external actor to system
Process Sale Scenario
system as black box
the name could be "NextGenPOS" but "System" keeps it simple
the ":" and underline imply an instance, and are explained in a later chapter on sequence diagram notation in the UML
a message with parameters
it is an abstraction representing the system event of entering the payment data by some mechanism
description, total
return value(s) associated with the previous message
an abstraction that ignores presentation and medium
the return line is optional if nothing is returned
total with taxes
change due, receipt
makeNewSale
[ more items ]loop
makePayment
8. System logs completed sale and sends sale and payment information to the external Accounting system and Inventory system
Make Payment :Creating the Payment
1: makePayment(cashTendered)
1.1: create(cashTendered)
:Register :Sale
:Payment
makePayment(cashTendered)
by Controller by Creator and Low Coupling
Make Payment :Logging a Completed Sale
Who is responsible for knowing all the logged sales, and doing the logging?
1: makePayment(cashTendered)
1.1: create(cashTendered)
:Register s :Sale
:Payment
makePayment(cashTendered)
:Store
2: addSale(s)
completedSales: List<Sale>
2.1: add(s)
by Expert
note that the Sale instance is named's' so that it can be referenced as a parameter in messages 2 and 2.1
makePayment:Calculating the Balance
The Process Sale use case implies that the balance due from a payment be printed on a receipt and displayed somehow.
7a. Paying by cash:1 收银员输入收取的现金数额2 系统给出应找的余额,并弹出现金抽屉3 收银员放入收取的现金,并拿出应找的余额给顾客
4 系统记录现金支付
Model-View Separation principle, we should not concern ourselves with how the balance will be displayed or printed
s :Sale pmt: Payment1: amt = getAmountbal = getBalance
2: t = getTotal
{ bal = pmt.amount - s.total }
startUp
StartUp 的开始
The startUp system operation occurs when a manager powers on the POS system and the software loads.
control will remain in the UI layer (such
as a Java JFrame) after the initial domain object is created.
Choosing the Initial Domain Object
StartUp启动时对数据库的操作
ProductSpecification 实例存储在存储介质如关系数据库或对象数据库中StartUp 时,若 ProductSpecification 对象数量不多,可全部加载到内存
若很多,消耗内存和时间太多,可在需要时才装载
StartUp 创建其他哪些对象
:Store :Register
pc:ProductCatalog
create 2: create(pc)
1: create
1.2: loadProdSpecs()
descriptions:Map<ProductDescription>
1.1: create
1.2.2*: put(id, pd)
1.2.1*: create(id, price, description)
pd:ProductDescriptionthe * in sequence number indicates the
message occurs in a repeating section
pass a reference to the ProductCatalog to the Register, so that it has permanent visibility to it
by Creatorcreate an empty collection object
:Register
Cashier
:ProcessSaleJFrame
actionPerformed( actionEvent )
1: enterItem(id, qty)? system event
UILayer
DomainLayer
presses button
:Register
Cashier
:ProcessSaleJFrame
actionPerformed( actionEvent )
1: enterItem(id, qty)
2 [no sale] : s = getSale : Sale
UILayer
DomainLayer
s : Sale
3: t = getTotal
presses button
用例实现和 UP
用例实现是 UP 设计模型的一部分建议并行画类图和交互图
初始阶段:设计模型和用例实现通常不做,因为涉及详细的设计决策,而初始阶段尚不成熟细化阶段:创建体系结构上重要的或风险较大的用例实现构造阶段:为剩下的设计问题创建用例实现
GRASP: 设计带职责的对象
五个 GRASP 模式应用 GRASP 实现 Process Sale 用例可见性设计类图设计
可见性设计
基本判断 :若对象 A 向对象 B 发消息,则 B 必须对 A
是可见的
四种可见方式
Attribute visibility– B 是 A的属性 Parameter visibility—B 是 A 的方法的参数 Local visibility—B 是 A 的局部对象(非方法的参数) .
• Global visibility—B 是以某种方式全局可见的
属性可见
相对永久,最常见
public class Register
{
…
private ProductCatalog catalog;
…
}
属性可见
参数可见
相对临时的可见性,只在方法范围内可见可见性的第二种常见形式
局部可见
相对临时的可见性,只在方法范围内可见
两种常见情况创建局部实例,并赋给局部变量将方法执行的返回对象赋给局部变量
全局可见
相对永久的可见性C++全局变量Singleton pattern
GRASP: 设计带职责的对象
五个 GRASP 模式应用 GRASP 实现 Process Sale 用例可见性设计类图设计
类图设计
依据
交互图软件类和方法概念模型 类定义的细节
领域模型和设计类图
方法
Method Name Issues
Method Names—createcreate message 不同语言中实现不同
C++ ,自动或 new 调用构造器Java , new 构造器
初始化是常见的 activity, 通常 DCD 中可省略 creation-related methods and constructors from a DCD.
Method Names—Accessing MethodsgetXXX(), setXXX()high noise-to-value ratio , for n attributes,
there are 2n uninteresting methods.通常省略
Method Names—Multiobjects
Method Names—Language-Dependent Syntax生成代码时自动转换成相应的语言格式
加上关联
Adding Dependency Relationships
depict non-attribute visibility between classes; in other words, parameter, global, or locally declared visibility.
visibility marker for attribute or method
current iteration does not have many interesting member details; all attributes are private and all methods public.
Rose演示