GRASP: 设计带职责的对象

Preview:

DESCRIPTION

GRASP: 设计带职责的对象. 徐迎晓 xuyingxiao@126.com 复旦大学软件学院. 设计带职责的对象. 交互设计和职责分配的质量决定系统的质量 可维护性 可理解性 可重用性 可扩展性 好的面向对象设计原则可用于交互图设计和职责分配 — GRASP 模 式. GRASP :通用职责分配软件模式 General Responsibility Assignment Software Patterns 将职责分配给对象的基本原则. GRASP: 设计带职责的对象. 五个 GRASP 模式 应用 G RASP 实现 Process Sale 用例 - PowerPoint PPT Presentation

Citation preview

GRASP: 设计带职责的对象

徐迎晓xuyingxiao@126.com

复旦大学软件学院

设计带职责的对象交互设计和职责分配的质量决定系统的质量可维护性可理解性可重用性可扩展性

好的面向对象设计原则可用于交互图设计和职责分配— 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演示

Recommended