1、第17章 GRASP:基于职责设计对象GRASP:Designing Objects with Responsibilities第1页,共48页。图17-1 制品关系(强调了对OO设计的影响第2页,共48页。职责和方法 UML定义职责定义职责(Responsibility)为为“类元的契约或义务。类元的契约或义务。方法方法(Method)用来实现(履行)职责。用来实现(履行)职责。一个职责可能要许多类和方法一个职责可能要许多类和方法(method)来实现,也可能只来实现,也可能只要很少方法来实现,这是由职责的粒度要很少方法来实现,这是由职责的粒度(granularity)来决定来决定的。的。第
2、3页,共48页。职责可分成两类:“认知认知”责(责(knowing)“行为行为”职责(职责(doing)“知道知道”私有的封装数据私有的封装数据“知道知道”相关联的对象相关联的对象“知道知道”能够派生或计算出的事物能够派生或计算出的事物“做做”自身的一些事情。如创建一个对象或进行一自身的一些事情。如创建一个对象或进行一次计算。次计算。“做做”其它对象的初始化操作。其它对象的初始化操作。控制和协调其它对象的活动。控制和协调其它对象的活动。第4页,共48页。职责和交互图图17-2 职责与方法是相关的在在UML制品制品(artifacts)中,通常是在建立交互图的语境来中,通常是在建立交互图的语境来
3、考虑对象的职责分配,通过方法来实现职责。考虑对象的职责分配,通过方法来实现职责。第5页,共48页。设计模式(Patterns)富有经验的面向对象技术专家(或其它软件开发人员)为解富有经验的面向对象技术专家(或其它软件开发人员)为解决某些问题而设计的解决方案,可作为通用原则决某些问题而设计的解决方案,可作为通用原则(General Principles)和惯用法和惯用法(Idioms),用于指导软件设计。,用于指导软件设计。如果将这些原则和惯用法以一种结构化的形式加以描述,如果将这些原则和惯用法以一种结构化的形式加以描述,给出问题和解决方案,然后起一个名字。这就是给出问题和解决方案,然后起一个名
4、字。这就是(Patterns)。例如:例如:模式名:信息专家(模式名:信息专家(Information ExpertInformation Expert)问题:为了获取某些信息,分配职责给对象的基本原则是什么?问题:为了获取某些信息,分配职责给对象的基本原则是什么?解决方案:将职责分配给信息专家解决方案:将职责分配给信息专家 -含有满足职责所需信息的类。含有满足职责所需信息的类。设计模式是一些针对特定问题的成功的解决方案设计模式是一些针对特定问题的成功的解决方案第6页,共48页。GoF关于设计模式的著作 英文版于1994年出版 这本书被认为是设计模式的“圣经”,它描述了23个OO设计模式 这本
5、书的作者有四人Erich Gamma,Richard Helm,Ralph Johnson,John Vlissides,因此被称为GoF(Gang of Four,四人帮)设计模式 阅读该书要有一定的OO设计和编程知识(C+)学习GRASP和基本GoF模式是本课程的关键目标第7页,共48页。GRASP:分配职责通用原则的模式 作为设计模式来描述对象设计和职责分配的作为设计模式来描述对象设计和职责分配的基本原则。基本原则。GRASPGRASP模式:模式:创建者创建者(Creator)信息专家信息专家(Information Expert)低耦合低耦合(Low Coupling)控制器控制器(C
6、ontroller)高内聚高内聚(High Cohesion)eneral esponsibility ssignment oftware attern第8页,共48页。创建者(Creator)创建者创建者谁创建了谁创建了A A?如果以下条件之一成立,则如果以下条件之一成立,则可以将创建类可以将创建类A A实例的职责分配给类实例的职责分配给类B B。n B B包含了包含了A A对象;对象;B B组成聚集了组成聚集了A A;nB B记录了记录了A A;nB B紧密地使用紧密地使用A A;nB B具有具有A A的初始化数据的初始化数据第9页,共48页。问题:由谁创建Square对象图17-3 Mo
7、nopoly迭代1的领域模型第10页,共48页。图17-4 在动态模型中运用创建者模式图17-5 在设计模型的DCD中,Board与Square具有组成聚合关联。我们在静态模型中应用了创建者在动态和静态模型中应用创建者模式第11页,共48页。信息专家(Information Expert)信息专家(或专家)信息专家(或专家)给给对象分配职责的基本原则是什么?对象分配职责的基本原则是什么?将职责分配给具有完成该职责所需信息将职责分配给具有完成该职责所需信息的那个类的那个类第12页,共48页。问题:如果给定键值,谁知道Square对象的相关信息图17-6 应用专家模式第13页,共48页。低耦合(L
8、ow Coupling)低耦合低耦合如何减少因变化产生的影响?如何减少因变化产生的影响?分配职责以使分配职责以使(不必要的不必要的)耦合保持在较低耦合保持在较低的水平。使用该原则对可选方案进行评估的水平。使用该原则对可选方案进行评估第14页,共48页。图17-7 评介耦合对设计影响此方案中Dog与Board都必须知道Square,而上一方案只有Board知道Square,所以上一方案耦合度更低。第15页,共48页。为什么期望低耦合 因为低耦合往往能够减少修改软件所需的时间、工作量和缺陷。第16页,共48页。创建者模式与低耦合创建者模式支持低耦合度创建者模式支持低耦合度,意味着具有较低的依赖关系
9、和意味着具有较低的依赖关系和较高的重用机会。因为被创建的类很可能早已经对创建者较高的重用机会。因为被创建的类很可能早已经对创建者类可见(即在创建者类已有方法涉及被创建者类),耦合类可见(即在创建者类已有方法涉及被创建者类),耦合程度不会增加。程度不会增加。第17页,共48页。信息专家模式与低耦合 信息专家模式支持低耦合度。因为信息专家模式把职责分配给拥有完成职责所需信息的对象。如果我们把职责分配给其他对象,则信息需要被这些对象共享会增加耦合度。第18页,共48页。控制器(Controller)控制器控制器在在UIUI层之上首先接收和协调层之上首先接收和协调(控制控制)系统操作的对象是什么?系统
10、操作的对象是什么?将接收或处理系统事件消息的职责分派给代表下列事务将接收或处理系统事件消息的职责分派给代表下列事务的类:的类:n代表全部代表全部“系统系统”或或“根对象根对象”,如,如MonopolyGameMonopolyGame对象对象n代表运行软件的设备,如代表运行软件的设备,如PhonePhone,BankCashMachineBankCashMachinen代表用例或会话出现。通常命名为代表用例或会话出现。通常命名为 HandlerHandler,SessionSession。如,如,PlayMonopolyGameHandlerPlayMonopolyGameHandler。第19
11、页,共48页。问题:谁首先来处理playGame系统系统图17-8 Monopoly游戏的SSD。注意playGame操作第20页,共48页。根据模型与视图分离原则,UI对象不应当包括业务逻辑,应该把请求委派给领域层的对象。图17-9 谁是用于playGame系统操作的控制器第21页,共48页。如果只有少数几个系统操作,可以选择代表全部“系统”或“根对象”。图17-10 应用控制器模式-使用MomopolyGame。所UI层与软件对象的领域层连接起来 第22页,共48页。高内聚(High Cohesion)高内聚高内聚怎样使对象保持有内聚、可理解和可管理,同时怎样使对象保持有内聚、可理解和可管
12、理,同时具有支持低耦合的附加作用?具有支持低耦合的附加作用?职责分配应保持高内聚,依此来评估备选方职责分配应保持高内聚,依此来评估备选方案。案。第23页,共48页。什么是高内聚度(什么是高内聚度(High Cohesion)是对一个类中的各个职责之间是对一个类中的各个职责之间相关程度相关程度和和集中程集中程度度的度量。的度量。一个具有一个具有高度相关职责高度相关职责的类并且这个类所能完成的工的类并且这个类所能完成的工作量不是特别巨大,那么它就具有高内聚度。作量不是特别巨大,那么它就具有高内聚度。包括两个意思:包括两个意思:不要给一个类分派太多的职责,在履行职责时尽量将部分职责分派给有不要给一个
13、类分派太多的职责,在履行职责时尽量将部分职责分派给有能力完成的其它类去完成。能力完成的其它类去完成。不相关的职责不要分派给同一个类。不相关的职责不要分派给同一个类。第24页,共48页。图17-11 对比不同设计的内聚程度左侧的方案中,MonopolyGame对象自己完成全部工作右侧方案中,MonopolyGame为playGame请求对工作进行了委派第25页,共48页。GRASP在NextGen POS设计中的示例第26页,共48页。创建者模式示例:谁该负责创建SalesLineItem?SaletimeSalesLineItemquantityProductDescriptiondescri
14、ptionpriceitemIDDescribed-by*Contains1.*11图17-12 部分领域模型第27页,共48页。Sale,因为它包含了SalesLineItem:Register:SalemakeLineItem(quantity):SalesLineItemcreate(quantity)图17-13 创建SalesLineItem第28页,共48页。信息专家示例:谁应当负责了解销售的总额SaletimeSalesLineItemquantityProductDescriptiondescriptionpriceitemIDDescribed-by*Contains1.*1
15、1图17-14 Sale的关联答案:查找具有完成职责所需信息的类。1)如果DCD中存在相关类,则在DCD中查找2)否则查看领域模型,并尝试利用(或扩充)它的表示,以激发相应设计类的创建第29页,共48页。Sale的新职责图17-15 部分交互图和类图第30页,共48页。SalesLineItem的新职责图17-16 计算Sale的总额第31页,共48页。ProductDescription的新职责图17-17 计算Sale的总额第32页,共48页。低耦合模式示例:谁负责创建Payment:Registerp:Payment:SalemakePayment()1:create()2:addPay
16、ment(p)图17-18 Register创建PaymentRegister记录了PaymentSale具有初始化Payment的数据(支付总额),另支持是针对Sale进行的方案一(创建者模式):方案一(创建者模式):第33页,共48页。:Register:Sale:PaymentmakePayment()1:makePayment()1.1.create()图17-19 Sale创建Payment方案二(创建者模式):方案二(创建者模式):结论:方案二耦合度更低。禁忌:高耦合对于稳定和普遍使用的元素而言不是问题同。如Java库。第34页,共48页。控制器模式示例:enterItem,end
17、Sale等系统操作的控制器是谁?SystemendSale()enterItem()makeNewSale()makePayment().图17-20 NextGen POS应用中的若干系统操作第35页,共48页。图17-21 哪个对象应该是enterItem的控制器哪个对象应该是enterItem的控制器第36页,共48页。可能的选择:1.代表整个“系统”、“根对象”、装置或子系统:Register,POSSystem2.代表用例场景中所有系统事件的接收者或处理者:ProcessSaleHandler,ProcessSaleSession.:RegisterenterItem(id,quan
18、tity):ProcessSaleHandlerenterItem(id,quantity)图17-22 控制器的选择第37页,共48页。不同方案的系统操作分配图17-23 系统操作的分配第38页,共48页。关于控制器模式的讨论 控制器设计中的常见缺陷是分配的职责过多。这时,控制器会具有不良(低)内聚,从而违反了高内聚的原则 准则:正常情况下,控制器应当把需要完成的工作委派给其它对象。控制器只是协调或控制这些活动,本身并不完成大量工作。UP和Jacobson的原有对象方法中,有边界对象(接口的抽象),实体对象(领域软件对象)和控制对象(控制器模式中的用例处理者)的概念。控制器模式的重要结果是,
19、UI对象和UI层不应具有实现系统事件的职责。系统操作应该在应用逻辑层或领域层完成。第39页,共48页。控制器在Web UI和服务器的应用 在Web页面中混入应用逻辑是ASP.NET程序设计中常用的、脆弱的编程类型。服务器端的Web UI框架(如:Structs)包含Web-MVC(模型-视图-控制器)模式的概念。Web-MVC中的控制器与GRASP控制器不同,前者是UI层的一部分,并且控制UI层的交互及页面流;后者是领域层的一部分,它控制或协调工作请求的处理,它根本不知道所用的UI技术是什么?第40页,共48页。UI层与控制器交互的编程示例 使用Java Swing的实现:富客户端UI P22
20、2 使用Java Structs实现,客户端浏览器和WebUI P224第41页,共48页。浮肿的控制器浮肿的控制器 在系统中只有一个简单的控制器接收所有在系统中只有一个简单的控制器接收所有的系统事件,并且系统事件非常多。的系统事件,并且系统事件非常多。控制器本身执行许多实现系统事件必需的控制器本身执行许多实现系统事件必需的任务,而没有把工作委托给别的类。任务,而没有把工作委托给别的类。控制器本身具有许多属性,并维护着系统控制器本身具有许多属性,并维护着系统或者领域中本应该分布到其它对象的大量或者领域中本应该分布到其它对象的大量信息,或在别处可以找到的重复信息。信息,或在别处可以找到的重复信息
21、。第42页,共48页。增加控制器。使用用例控制器,而不是外观控制器增加控制器。使用用例控制器,而不是外观控制器 航空预订系统示例航空预订系统示例 设计控制器,使它把完成每个系统操作的职责委派给其设计控制器,使它把完成每个系统操作的职责委派给其它对象它对象第43页,共48页。界面层不处理系统事件界面层不处理系统事件-期望的期望的图17-24 UI层到领域层之间所期望的耦合第44页,共48页。界面层不处理系统事件界面层不处理系统事件-不期望的不期望的图17-25 UI层到领域层所不太期望的耦合第45页,共48页。:Register:SaleaddPayment(p)p:Paymentcreate(
22、)makePayment()创建创建Payment类的对象的职责可以交类的对象的职责可以交给给Sale类去完成。类去完成。:Register履行履行makaPayment职责时要履行职责时要履行2个职责。个职责。高内聚模式示例:makePayment职责的分配方案一:方案一:Register创建Payment图17-26 Register创建Payment第46页,共48页。:Register:SalemakePayment():Paymentcreate()makePayment()创建创建Payment类的对象的职责类的对象的职责委派给委派给Sale类去完成。类去完成。这 样,这 样,:R e g i s t e r履 行履 行makaPayment职责的负担职责的负担减轻了。只需履行减轻了。只需履行1个职个职责责方案二:方案二:Sale创建Payment图17-27 Sale创建Payment此方案既支持高内聚又支持低耦合第47页,共48页。演讲完毕,谢谢观看!第48页,共48页。