细化迭代基础章PPT学习课件

上传人:牛*** 文档编号:99616694 上传时间:2022-06-01 格式:PPTX 页数:153 大小:5.81MB
收藏 版权申诉 举报 下载
细化迭代基础章PPT学习课件_第1页
第1页 / 共153页
细化迭代基础章PPT学习课件_第2页
第2页 / 共153页
细化迭代基础章PPT学习课件_第3页
第3页 / 共153页
资源描述:

《细化迭代基础章PPT学习课件》由会员分享,可在线阅读,更多相关《细化迭代基础章PPT学习课件(153页珍藏版)》请在装配图网上搜索。

1、第三部分第三部分 细化迭代细化迭代1 基础基础(3)主要内容主要内容 第17章 GRASP 基于职责设计对象 第18章 使用GRASP的对象设计示例第第17章章 GRASP:基于职责设计对象:基于职责设计对象 引言引言 我们已经创建了领域模型 确定有什么样的方法,属于谁,对象之间如何交互,这是开发面向对象系统的核心 但是如何做? GRASP模式是帮助我们理解详细的原则和所需要的思考方法的学习工具 这些模式与如何将责任分配给相关类GRASP :General Responsibility Assignment Software Pattern GRASP的核心是自己干自己能干的事,自己只干自己的

2、 事17.1 UML与设计原则与设计原则 最关键的软件开发工具是受过良好设计原则训练的思维,而不是UML或任何其他技术17.2 对象设计:输入、活动和输出的示例对象设计:输入、活动和输出的示例输入输入 对象设计中的活动 对具有创造性、最苦难的部分建模。 运用各种OO设计原则给协作中的对象分配职责 对象设计的输出: 针对设计中的难点创建UML交互图、类图和包图 UI的草图和原型 数据库模型 报表的草图和原型17.3 职责和职责驱动设计职责和职责驱动设计 职责职责:类元的契约或义务:类元的契约或义务 对象的行为职责对象的行为职责: 自身执行一些行为,例如创建对象或计算自身执行一些行为,例如创建对象

3、或计算 初始化其他对象中的动作初始化其他对象中的动作 控制或者协调其它对象的活动控制或者协调其它对象的活动如:如:Sale负责创建负责创建SalesLineItem 对象的认知职责对象的认知职责 对对私有封装数据的认知私有封装数据的认知 对相关对象的认知对相关对象的认知 对其能够导出或计算的事物的认知对其能够导出或计算的事物的认知如:如:Sale负责认知其总额负责认知其总额职责职责&方法方法 职责不等同于方法,职责是一种抽象,而方法实现了职责,该方法可以单独动作,也可以与其他方法和对象协作。例如:Sale 类可以定义一个或多个方法来计算总价 命名为 getTotal的方法 为了完成此职责,Sa

4、le可能与其它对象协作,例如发送getSubTotal 消息给每一个SalesLineItem 对象,来获取每一个类别的价格17.5职责、职责、GRASP和和UML图之间的联系图之间的联系 职责可以通过编程实现 或者可以通过创建交互图来进行分配 建议采用GRASP的基本原则职责与方法是相关的职责与方法是相关的17.6 什么是模式什么是模式 在我们人类社会中,许多方面的成功经验都可以归结为模式在我们人类社会中,许多方面的成功经验都可以归结为模式 事实上,教育的重要目标就是把学习的模式从一代传向下一代事实上,教育的重要目标就是把学习的模式从一代传向下一代 在在OO设计中,设计中,模式模式是对问题和

5、解决方案的已命名描述是对问题和解决方案的已命名描述 优秀的模式的意图是将已有的经过验证的知识、惯用法和原则汇优秀的模式的意图是将已有的经过验证的知识、惯用法和原则汇编起来编起来“新模式新模式”矛盾修饰语。矛盾修饰语。 模式是一种学习工具,可以用来命名、表示和记忆那些基本和经模式是一种学习工具,可以用来命名、表示和记忆那些基本和经典的设计思想典的设计思想成为一个软件设计大师成为一个软件设计大师 首先学习规则 例如,算法,数据结构和软件语言 然后学习原则 例如,结构化编码,模块化编码,面向对象编码,遗传编码等等 但是, 为了真正掌握软件设计,还必须学习其它大师的设计 这些设计包含了必须理解,记忆和

6、重复运用的模式 这种模式也是非常多的模式优点模式优点 模式对专家的知识和设计中的优缺点进行了显示获取,并尽力使这种专家知识被广泛应用 模式可以改进开发者之间的沟通 模式名字构成一个词汇集 模式有助于面向对象技术的推广注意点注意点 不要把所有的东西都作为一个模式 开发战略性的领域模式,并重用现存的战术型模式 模式作者,应用开发者和领域专家之间的密切合作 在文档中清楚表明何时可以应用,何时不可以应用GOF关于设计模式的著作关于设计模式的著作 Kent Beck 首先提出软件命名模式的思想 1994年 模式的“圣经”Design Patterns极为畅销 Gamma、Helm、Johnson 和 V

7、lissides GRASP定义了9个基本OO设计原则和基本设计构件。 某人的模式是其他人的原始构造块。17.8 使用使用GRASP进行对象设计的简短示例进行对象设计的简短示例 本案例用到了本案例用到了9个个GRASP模式中的以下几个模式中的以下几个: 创建者创建者(Creator) 信息专家信息专家(Information Expert) 低耦合低耦合(Low Coupling) 控制器控制器(Controller) 高内聚高内聚(High Cohesion)创建者创建者(Creator) 问题:谁创建Square对象?名称:名称:问题:谁创建了问题:谁创建了A?解决方案(可被视作建议):如

8、果以下条件之一为真时(越多越好),将解决方案(可被视作建议):如果以下条件之一为真时(越多越好),将创建类创建类A示例的职责分配给类示例的职责分配给类B: B“包含包含”或组成聚集了或组成聚集了A. B记录记录A. B紧密地使用紧密地使用A. B具有具有A的初始化数据的初始化数据.LRG: 不用不用AB324或或ZC17命名命名的理由的理由从领域模型中获取灵感,使从领域模型中获取灵感,使Board软件对象包含软件对象包含Square软件对象。软件对象。运用创建者模式运用创建者模式需要循环创建需要循环创建40个方个方格格信息专家信息专家(Information Expert) 问题:问题: 如果

9、给定键值,谁知道如果给定键值,谁知道Square对象的相关信息?对象的相关信息? s= getSquare(name)名称:名称:问题:给对象分配职责的基本原则是什么?问题:给对象分配职责的基本原则是什么?解决方案(建议):把职责分配给具有完成该职责所需信解决方案(建议):把职责分配给具有完成该职责所需信息的那个类。息的那个类。为了能够检索和表示任何为了能够检索和表示任何Square,s= getSquare(name) ,某个对,某个对象必须知道所有象必须知道所有Square信息(持有其信息)信息(持有其信息)Board聚集所有聚集所有Square对象,因此对象,因此Board具有履行此职责

10、所必需的信具有履行此职责所必需的信息,所以将获知特定息,所以将获知特定Square的职责分配给的职责分配给Board对象对象低耦合低耦合(Low Coupling)问题:为什么是问题:为什么是Board而不是而不是Dog(某个任意类)?(某个任意类)?耦合耦合: 就是对某元素与其它元素之间的连接、感知和依赖的量。就是对某元素与其它元素之间的连接、感知和依赖的量。元素元素: 既可以是功能、对象也可以指系统、子系统、模块。既可以是功能、对象也可以指系统、子系统、模块。A与与B耦合:耦合:假如一个元素假如一个元素A去连接元素去连接元素B,或者通过自己的方法可以感知,或者通过自己的方法可以感知B,或,

11、或者当者当B不存在的时候就不能正常工作,那么就说元素不存在的时候就不能正常工作,那么就说元素A与元素与元素B耦合。耦合。名称:低耦合名称:低耦合(Low Coupling)问题:如何减少因变化产生的影响?问题:如何减少因变化产生的影响?解决方案(建议):分配职责以使(不必要的)耦合保持在较低的水平。用解决方案(建议):分配职责以使(不必要的)耦合保持在较低的水平。用该原则对可选方案进行评估。该原则对可选方案进行评估。为什么是为什么是Board而不是而不是Dog?Dog和和Board都需要知道都需要知道Square,耦合高!,耦合高!信息专家模式支持低耦合信息专家模式支持低耦合 回到信息专家的动

12、机:该原则可以知道我们作出支持低耦合的回到信息专家的动机:该原则可以知道我们作出支持低耦合的选择选择 专家让我们寻找这样的对象,该对象具有职责所需的大部分信专家让我们寻找这样的对象,该对象具有职责所需的大部分信息,并把职责分配给该对象。息,并把职责分配给该对象。 如果分配给如果分配给Dog,则存在更多的信息或对象必须被某些事物所,则存在更多的信息或对象必须被某些事物所分享,而这些事物远离信息源或对象的本源。分享,而这些事物远离信息源或对象的本源。控制器控制器MVS 原则:原则:UI 对象不应当包含应用逻辑或业务逻辑,如:计算游戏者的移动!应对象不应当包含应用逻辑或业务逻辑,如:计算游戏者的移动

13、!应该把请求委派给领域层的领域对象!该把请求委派给领域层的领域对象!w 问题:怎样将问题:怎样将UI层连接到应用逻辑层?从层连接到应用逻辑层?从UI层接收层接收playGame消息的第一个对消息的第一个对象是象是Board吗?或者其他对象?吗?或者其他对象?w 控制器控制器(Controller)模式定义模式定义名称:控制器名称:控制器(Controller)问题:在问题:在UI层之上首先接收和协调(层之上首先接收和协调(“控制控制”)系统操作的对象是什)系统操作的对象是什么?么?解决方案(建议):把职责分配给能代表下列选择之一的对象:解决方案(建议):把职责分配给能代表下列选择之一的对象:代

14、表全部代表全部“系统系统”、“根对象根对象”、运行软件的设备或主要的子系运行软件的设备或主要的子系统统代表发生系统操作的用例场景代表发生系统操作的用例场景如:如:MonopolyGame,System如:如:PlayMonoployGameHandler如:电话机或银行兑钞机如:电话机或银行兑钞机应用控制器模式应用控制器模式使用使用MonopolyGame高内聚高内聚(High Cohesion)MonopolyGame对象自己完对象自己完成全部工作成全部工作为为playGame请求对工作进行请求对工作进行了委派和协调了委派和协调名称:高内聚名称:高内聚(High Cohesion)问题:怎样

15、使对象保持有内聚、可理解和可管理,同时具有支持低耦问题:怎样使对象保持有内聚、可理解和可管理,同时具有支持低耦合的附加作用?合的附加作用?解决方案(建议):职责分配应该保持高内聚,以此来评估备选方案。解决方案(建议):职责分配应该保持高内聚,以此来评估备选方案。右侧的设计方案比左侧的方案更好地支持了高内聚。右侧的设计方案比左侧的方案更好地支持了高内聚。高内聚高内聚(High Cohesion)模式定义模式定义17.9 在对象设计中应用在对象设计中应用GRASP GRASP (General Responsibility Assignment Software Patterns)通用职责分配软件

16、模式)通用职责分配软件模式 9个模式如下个模式如下:w 创建者(创建者(Creator)w 信息专家(信息专家(Information Expert)w 低耦合(低耦合(Low Coupling)w 控制器(控制器(Controller)w 高内聚(高内聚(High Cohesion)w 多态性多态性(Polymorphism)w 纯虚构纯虚构(Pure Fabrication)w 间接性间接性(Indirection)w 防止变异防止变异(Protected Variations)本章先介绍前五个,后面的四个将于本章先介绍前五个,后面的四个将于25章介绍章介绍17.10 创建者(创建者(Cr

17、eator) 问题问题 谁来负责创建某些类的新实例谁来负责创建某些类的新实例? 在面向对象系统中对象的创建是一个最普通的活动,如果分配在面向对象系统中对象的创建是一个最普通的活动,如果分配的好,设计就能够支持低耦合,提高清晰度、封装性和可复用的好,设计就能够支持低耦合,提高清晰度、封装性和可复用性。性。 我们需要一个分配创建责任的通用原则我们需要一个分配创建责任的通用原则解决方案解决方案 将创建类A的实例的责任分配给类B,如果一个或多个下面的条件为真(越多越好): B 聚合了(aggregates) A 对象 B 包含了(contains)A对象 B 记录了(records)A对象的实例 B

18、密切使用(closely uses)A对象 B 拥有传递给创建A所需要的初始化数据 ( 因此B是创建A的专家) B 是对象A的创建者示例示例 在POS应用,谁需要负责创建 SalesLineItem(条目) 实例呢?SaledatetimeSalesLineItemquantityProductSpecificationdescriptionpriceitemIDDescribed-by*Contains1.*11部分领域模型部分领域模型sale包含了(聚集)许多SalesLineItem 对象,所以是良好候选者。: Register: Salem akeLineItem (quantity)

19、: SalesLineItemcreate(quantity)讨论讨论 组合对象是创建其组成部分的良好候选者。组合对象是创建其组成部分的良好候选者。 有时创建者可以通过寻找初始化数据的类来确定创建者,这些有时创建者可以通过寻找初始化数据的类来确定创建者,这些数据将在创建过程中传递给被创建者。数据将在创建过程中传递给被创建者。 例如,假设例如,假设Payment 的一个实例需要被初始化,在创建时,的一个实例需要被初始化,在创建时,需要携带需要携带 Sale 总额信息。由于总额信息。由于Sale 知道总价,知道总价,Sale 是是Payment的侯选创建者的侯选创建者。禁忌禁忌许多时候,创建过程有

20、很强的复杂性,例如由于性能原因需要回许多时候,创建过程有很强的复杂性,例如由于性能原因需要回收实例,依据外部属性值有条件的创建一组相近似的类的一个收实例,依据外部属性值有条件的创建一组相近似的类的一个实例,实例,如:如: XXXFactory.newInstance() 来创建实例。来创建实例。建议采用建议采用Factory类类 (抽象、具体工厂类)(抽象、具体工厂类)参见参见26.4节节优点优点 低耦合,意味者较低的维护依赖性和较高的复用性,已经有对低耦合,意味者较低的维护依赖性和较高的复用性,已经有对被创建类的可见性被创建类的可见性相关模式或原则:相关模式或原则: 低耦合低耦合 具体工厂和

21、抽象工厂具体工厂和抽象工厂 整体整体-部分部分17.11 信息专家(专家)信息专家(专家) 问题:给对象分配职责的基本原则是什么?问题:给对象分配职责的基本原则是什么? 设计模型可能定义成百上千个软件对象,一个应用中也可能需要将成百上千项责任进行分配设计模型可能定义成百上千个软件对象,一个应用中也可能需要将成百上千项责任进行分配 目的:易于理解,维护,扩展和重用目的:易于理解,维护,扩展和重用 解决方案解决方案 将责任分配给信息专家,它具有实现这个职责所必需的信息。将责任分配给信息专家,它具有实现这个职责所必需的信息。示例示例 NextGEN POS 应用,某个类需要知道销售总额应用,某个类需

22、要知道销售总额 谁负责了解销售总额谁负责了解销售总额?信息专家建议:信息专家建议:具有确定总额所需信息的那个对象类具有确定总额所需信息的那个对象类现在需要回答的问题:现在需要回答的问题:哪里找所需信息的类?哪里找所需信息的类? 如果已经有设计模型,并且包含了相关的类,首先关注它们。如果已经有设计模型,并且包含了相关的类,首先关注它们。 否则,查看领域模型否则,查看领域模型部分领域模型部分领域模型SaledatetimeSalesLineItemquantityProductSpecificationdescriptionpriceitemIDDescribed-by*Contains1.*11

23、确定总额需要哪些信息?销售的所有销售的所有SalesLineItem实例及其小计之和实例及其小计之和SalesLineItem.quantity 信息专家:信息专家:SalesLineItemProcuctionDescription.price 信息专家:信息专家:ProcuctionDescriptionS aletim e.getTotal()S alesLineItemquantitygetS ubtotal()P roductD escriptiondescriptionpriceitem IDgetP rice()N ew m ethod:P roductD escription1

24、.1: p := getP rice() 1 *: st = getS ubtotal: S alet = getTotallineItem s i :S alesLineItem确定商品的小计需要知道哪些信息?确定商品的小计需要知道哪些信息?三个对象的设计类分配了如下职责:三个对象的设计类分配了如下职责: 设计类设计类职责职责Sale知道销售的总额知道销售的总额SalesLineItem知道商品的小计知道商品的小计ProductSpecification知道产品的价格知道产品的价格讨论讨论 当信息分布在不同的对象中,他们需要相互间通过消息进行交当信息分布在不同的对象中,他们需要相互间通过消息

25、进行交互以分担工作互以分担工作 在真实的世界中,对象可能没有生命的,但是在软件中,对象在真实的世界中,对象可能没有生命的,但是在软件中,对象是是“活着的活着的”或者或者“有生命的有生命的”,并且它们可以承担责任,完,并且它们可以承担责任,完成任务。成任务。例如:例如:在企业中,谁应该作盈利或亏损的结论?在企业中,谁应该作盈利或亏损的结论?答案:首席财务官!答案:首席财务官!但是首席财务官必需需要会计师的借贷报告但是首席财务官必需需要会计师的借贷报告!禁忌禁忌 没有万能药 专家模式可能在某些情况中造成耦合和内聚 例如,谁负责将Sale保存在数据库?专家建议将此职责分配给Sale。但是,如果这样的

26、话,会导致: 内聚、耦合及冗余方面的问题。 违反基本的架构原则:即设计要分离主要的系统关注。 我们应该将应用逻辑放在一个地方,将数据库逻辑放在另外一个地方 (持久化服务子系统)优点优点 实现了信息封装,因为对象使用它们自己的信息完成任务:低耦合 行为分布在拥有所需要的信息的类上相关模式: 低耦合 高内聚17.12 低耦合低耦合 问题:怎样降低依赖性,减少变化带来的影响,提高重用性。 耦合是对一个元素与其他元素的连接,拥有知识,依赖等关系的强烈程度的度量。 高耦合造成: 相关的类的变化造成本体被迫变化 难以单独的理解 难以重用,牵涉到它所依赖的类。 解决方案 分配职责,使得耦合性尽可能的低示例示

27、例 我们需要创建一个Payment 实例并将其与Sale关联。PaymentRegisterSale方案方案1 (创建者模式)创建者模式): R egisterp : P aym ent:S alem akeP aym ent() 1: create() 2: addP aym ent(p) Register记录了记录了Payment,所以,所以Register为创建为创建 Payment的候选者。的候选者。耦合:耦合:Register与与Payment Register与与Sale Payment与与Sale方案方案2:由Sale来创建Payment对象耦合:Register与Sale Sa

28、le 与Payment: Register:Sale:PaymentmakePayment()1: makePayment()1.1. create()讨论讨论 低耦合是一个在设计中时时需要记住的原则;它也是需要一直低耦合是一个在设计中时时需要记住的原则;它也是需要一直考虑的目标。这是设计者用来评估设计决策时运用的一个评价考虑的目标。这是设计者用来评估设计决策时运用的一个评价准则。准则。 不能脱离专家和高内聚等其他模式孤立地考虑。不能脱离专家和高内聚等其他模式孤立地考虑。 子类和超类有很强的耦合性。子类和超类有很强的耦合性。 没有绝对的度量标准来衡量耦合程度的高低。没有绝对的度量标准来衡量耦合

29、程度的高低。 低耦合的极端例子:类之间没有耦合。低耦合的极端例子:类之间没有耦合。 对象之间要有适度的耦合。对象之间要有适度的耦合。禁忌禁忌 对稳定的元素和普遍的元素的高耦合一般不是一个问题对稳定的元素和普遍的元素的高耦合一般不是一个问题 例如,一个例如,一个Java J2EE应用对应用对 Java库库 (java.util, 等等)的耦等等)的耦合没有问题合没有问题, 因为它们是稳定的,并被普遍使用因为它们是稳定的,并被普遍使用权衡利弊权衡利弊高耦合本身不是问题所在,要避免和不稳定元素之间的高耦合,如高耦合本身不是问题所在,要避免和不稳定元素之间的高耦合,如接口,实现等。接口,实现等。 例子

30、:例子:NextGen项目中,系统要连接不同的第三方税金计算器,项目中,系统要连接不同的第三方税金计算器,应该为这种实际的变化点进行低耦合设计。应该为这种实际的变化点进行低耦合设计。优点:优点: 其他组件中的变更不会造成影响其他组件中的变更不会造成影响 由于分离,便于理解由于分离,便于理解 方便重用方便重用相关模式相关模式 防止变异防止变异17.13:控制器(:控制器(Controller) 问题:在问题:在UI层之上首先接收和协调系统操作的第一个对象是什么?层之上首先接收和协调系统操作的第一个对象是什么? 谁应该为处理输入系统事件负责谁应该为处理输入系统事件负责? 一个控制器是一个没有用户界

31、面的对象,负责接收和处理系统事件。控制一个控制器是一个没有用户界面的对象,负责接收和处理系统事件。控制器定义了系统操作的方法器定义了系统操作的方法 解决方案解决方案 将接收和处理系统事件消息的责任分配给代表下列方面的类将接收和处理系统事件消息的责任分配给代表下列方面的类: 代表整个系统,设备或子系统代表整个系统,设备或子系统 代表用例场景,在该场景中发生系统事件,通常命名为代表用例场景,在该场景中发生系统事件,通常命名为Handler、 Coordinator或或Session(用例或会话控制器)(用例或会话控制器)示例示例 在NextGen应用中,有下列几个系统操作SystemendSale

32、()enterItem()makeNewSale()makePayment(). . . 代表整个系统,设备或子系统 Register,POSSystem 代表一个与系统事件相对应的用例场景 ProcessSaleHandler,ProcessSaleSession:RegisterenterItem(id, quantity):ProcessSaleHandlerenterItem(id, quantity)根据控制器模式,给出两个选择根据控制器模式,给出两个选择讨论讨论 可以使用同一个控制类来处理一个用例中的所有系统事件以维可以使用同一个控制类来处理一个用例中的所有系统事件以维护控制器中有

33、关用例状态的信息护控制器中有关用例状态的信息 一般,控制器将需要完成的工作分配给其他对象;它负责协调一般,控制器将需要完成的工作分配给其他对象;它负责协调或者控制活动,自己不做太多工作。或者控制活动,自己不做太多工作。外观控制器外观控制器 它代表了整个系统,设备或一个子系统它代表了整个系统,设备或一个子系统 它提供了从它提供了从UI层往其他层的服务调用的主要入口层往其他层的服务调用的主要入口 对整个物理单元的抽象,例如对整个物理单元的抽象,例如Register, TelecommSwitch, Phone 或或 Robot代表了整个软件系统的类,例如代表了整个软件系统的类,例如POSSyste

34、m设计者选择用来表示整个系统,子系统的其他概念,例如如果是设计者选择用来表示整个系统,子系统的其他概念,例如如果是一个游戏软件,选择一个游戏软件,选择ChessGame 什么时候我们选择外观控制器什么时候我们选择外观控制器?当没有当没有“过多过多”的系统事件,或者的系统事件,或者UI不能把系统事件消息重定向不能把系统事件消息重定向到其他控制器(如在消息处理系统中)时,选择外观控制器是合到其他控制器(如在消息处理系统中)时,选择外观控制器是合适的。适的。用例控制器用例控制器 对每一个用例设置一个单独的控制器 这是支持系统的人工造物 例如,在NextGen应用中,例如Process Sale 等用

35、例可以与 ProcessSaleHandler 类关联 什么时候我们选择用例控制器? 当有太多的系统事件并设计不同的过程,用例控制器是一个好的选择。它将处理它们的任务分配给那些可管理的单独的类,也提供了一个获知和推理目前进行中的场景的当前状态的基础。 在统一过程中: 边界对象(Boundary Objects) 是接口的抽象 实体对象(Entity Objects) 是独立于应用(经常是持久性)领域软件对象 控制对象(Control Objects) 是控制器模式中描述的用例处理器优点优点 提高了重用的可能性,提供了可插拔的接口提高了重用的可能性,提供了可插拔的接口-它保证了接口层不它保证了接

36、口层不处理应用逻辑处理应用逻辑 对用例的状态进行推理对用例的状态进行推理 保证系统操作以合法的顺序发生保证系统操作以合法的顺序发生问题和解决方案问题和解决方案 “浮肿的浮肿的”控制器(控制器(Bloated Controllers) 如果设计得不合理,控制类内聚性不强如果设计得不合理,控制类内聚性不强-不聚焦并处理了太多领域的责任不聚焦并处理了太多领域的责任 症兆症兆 一个控制类接收所有的系统事件一个控制类接收所有的系统事件 控制类自己处理了完成系统事件所需要的太多任务控制类自己处理了完成系统事件所需要的太多任务 控制器有太多的属性并维持了系统或领域的信息控制器有太多的属性并维持了系统或领域的

37、信息 解决办法解决办法 增加控制器(使用用例控制器,非外观控制器)增加控制器(使用用例控制器,非外观控制器) 设计控制器:把职责委派给其他对象设计控制器:把职责委派给其他对象actionPerformed( actionEvent ):Register: Cashier:SaleJFramepresses button1: enterItem(itemID, qty):Sale1.1: makeLineItem(itemID, qty)Interface LayerDomain Layersystem event messagecontroller接口层并不处理系统事件接口层并不处理系统事件接

38、口层到领域层之间所期望的耦合接口层到领域层之间所期望的耦合接口层到领域层所不太期望的耦合接口层到领域层所不太期望的耦合17.14:高内聚:高内聚 问题:怎样保持对象是有重点的、可理解的、可管理的,并且能够支持低耦合? 内聚是对一个元素的责任之间的关系是否密切相关和集中的度量 低内聚的类包含了很多无关的事情,或者承担了太多的工作。它们有下面这些的问题: 难以理解 难以重用 难以维护 脆弱; 常常受变化影响 解决方案 分配职责可保持较高的内聚性示例示例 我们需要创建我们需要创建(cash) Payment 的实例并将它与的实例并将它与Sale 关联关联 解决方案1: Register: Salea

39、ddPayment( p )p : Paymentcreate()makePayment()假如有假如有50个系统操作,都要由个系统操作,都要由Register接收。如果接收。如果Register要完成与每个操作要完成与每个操作都有关系的工作,它就会编成都有关系的工作,它就会编成“臃肿的臃肿的”、非内聚的对象。、非内聚的对象。解决方案2: Register: SalemakePayment() : Paymentcreate()makePayment()支持高内聚,又支持低耦合讨论讨论 这是一个需要时刻牢记的原则,就如同低耦合模式一样 高度内聚的类一般具有较少的方法,具有高度相关的功能,而且不

40、完成太多的工作另外一个经典原则:模块化设计另外一个经典原则:模块化设计 模块化是将系统分解成一组内聚的、松散耦合的模块的特性模块化是将系统分解成一组内聚的、松散耦合的模块的特性 通过创建具有高内聚的方法和类来促进模块化设计方法。在基通过创建具有高内聚的方法和类来促进模块化设计方法。在基本的对象级别上,我们为每个方法设计清晰和单独的目标,并本的对象级别上,我们为每个方法设计清晰和单独的目标,并且把一组相关关注置于一个类中,以此来实现模块化且把一组相关关注置于一个类中,以此来实现模块化内聚和耦合:内聚和耦合: “阴阴”和和“阳阳” 例如:考虑一个GUI窗口小部件类的做法: 绘制窗口 把数据存入数据

41、库 调用远程对象服务非内聚:(包含所有的功能)非内聚:(包含所有的功能)耦合高:(数据库,远程对象)耦合高:(数据库,远程对象)禁忌禁忌低内聚在某些情况下是可以接受的 将SQL语句放入每一个类遵循了内聚模式。 但是将SQL语句分离出来并归并在一个类中更合理,因为它需要特殊的技术,由SQL专家专门处理。 在分布应用中,为了改进性能,我们可以设置一个远程操作 setData 而不是分别设置 setName, setSalary 和 setHireDate.第第18 使用使用GRASP的对象设计示例的对象设计示例18.1 用例实现用例实现 用例实现(use-case realization)描述某个

42、用例基于协作对象如何在设计模型中实现。 UML图是描述用例实现的常用语言。 可以在用例实现的设计工作中应用对象设计的原则和模式。18.2 制品注释制品注释 SSD、系统操作、交互图和用例实现 考虑“处理销售”用例的SSD所确定的系统操作和场景 makeNewSale enterItem endSale makePayment 如果使用通讯图来描述用例实现,我们将绘制不同的通讯图来表示对每个系统操作消息的处理。对于顺序图也同样如此。 通信图用于显示用例实现 顺序图用于显示用例实现用例和用例实现用例和用例实现 用例是用例实现的首要输入用例是用例实现的首要输入 时刻记住:所记录的需求是不完善的时刻记

43、住:所记录的需求是不完善的 让客户尽量参与项目的整个过程让客户尽量参与项目的整个过程操作契约和用例实现操作契约和用例实现 有可能直接从用例的文字中设计用例实现有可能直接从用例的文字中设计用例实现 对某些复杂系统操作而言,契约可以用于增加描述细节对某些复杂系统操作而言,契约可以用于增加描述细节 契约契约CO2: enterItem操作操作: enterItem(ItemID: ItemID, quantity:integer)交叉引用交叉引用: 用例用例:处理销售处理销售前置条件前置条件:有正在处理的销售。有正在处理的销售。后置条件后置条件: 创建创建SalesLineItem的实例的实例 sl

44、i- 对于每一个契约,我们会依据对相关用例文本的对于每一个契约,我们会依据对相关用例文本的 思考,完成后置条件的状态变更,并设计消息的交互以满足需求。思考,完成后置条件的状态变更,并设计消息的交互以满足需求。1: makeLineItem(.)enterItem(id, qty)1.1: create(.):Register:Sale:SalesLineItem领域模型和用例实现领域模型和用例实现 选择合适的责任分配依赖于领域模型选择合适的责任分配依赖于领域模型 但是用例实现可能引起领域模型的修改但是用例实现可能引起领域模型的修改 概念概念 vs. 设计类设计类 领域模型可以用以启发我们在设计

45、模型中定义软件类并据此命名领域模型可以用以启发我们在设计模型中定义软件类并据此命名 设计类必须来源于概念?设计类必须来源于概念? 完全不是。完全不是。 发现早期遗漏的新概念,同时也经常会虚构出一些软件类,名称和目的可能会与领域模型完全无关。发现早期遗漏的新概念,同时也经常会虚构出一些软件类,名称和目的可能会与领域模型完全无关。 18.3 下一步工作下一步工作 对NextGen POS进行详细讨论。 同样对Monopoly案例研究进行详细讨论。18.4 NextGen迭代的用例实现迭代的用例实现初始和初始和“启动启动”用例用例 启动启动用例实现是设计语境,在该语境中要考虑创建大部分的用例实现是设

46、计语境,在该语境中要考虑创建大部分的“根根”或生命期长的对象。或生命期长的对象。 准则:准则:在编码时,首先要考虑编写在编码时,首先要考虑编写启动启动初始化的程序。初始化的程序。OO设计建模时,最后考虑设计建模时,最后考虑启动启动初始化,直到发现哪些是真正需要被创建和初始化的。初始化,直到发现哪些是真正需要被创建和初始化的。设计启动之前探讨设计启动之前探讨处理销售处理销售 用例实现用例实现如何设计如何设计 makeNewSalemakeNewSale 系统操作发生于当收银员在顾客到系统操作发生于当收银员在顾客到 达后有东西要买,开始一笔新的买卖时达后有东西要买,开始一笔新的买卖时选择控制类选择

47、控制类 依据控制者模式,下面是一些选择项:代表整个代表整个“系统系统”,设备或子系统,设备或子系统Store:根对象:根对象Register:运行软件特定设备:运行软件特定设备POSSystem:整个系统名称:整个系统名称代表一个用例场景中系统事件的接代表一个用例场景中系统事件的接收者或者处理者收者或者处理者ProcessSaleHandlerProcessSaleSession在设计模型中,该在设计模型中,该Register 是一个是一个软件对象软件对象。它不是一个真实的物理的收银台,。它不是一个真实的物理的收银台,而是一种软件抽象,选择这个名字可以减少领域和软件概念之间的表示鸿沟而是一种软

48、件抽象,选择这个名字可以减少领域和软件概念之间的表示鸿沟.由于只存在少量的系统操作,因此由于只存在少量的系统操作,因此Register就可以满足要求。就可以满足要求。创建新的创建新的Sale 软件对象软件对象Sale 必须被创建必须被创建: Creator 模式模式 谁来创建它呢谁来创建它呢?Register(登记簿)是记录(或登记)账户信息(例如销售)的事物。(登记簿)是记录(或登记)账户信息(例如销售)的事物。Register是记录是记录Sale的类的类Register 创建它,然后与之关联创建它,然后与之关联 当当Sale 创建后,它必须创建一个空的集合,以记录所有的将来要被添加的创建后

49、,它必须创建一个空的集合,以记录所有的将来要被添加的 SalesLineItem 实例实例 Register创建Sale,而Sale创建空集合。如何设计如何设计enterItementerItem 系统操作发生于当收银员输入一个系统操作发生于当收银员输入一个 购买商品的购买商品的itemID 和和 (可选可选)数量数量.w 契约契约CO2: enterItemw 操作操作: enterItem(itemID: ItemID, quantity: integer)w 交叉参考交叉参考: 用例:处理销售用例:处理销售w 前提条件前提条件: 正在进行的销售正在进行的销售w 后置条件后置条件:创建了创

50、建了SalesLineItem的实例的实例sli(创建实例)(创建实例)将将Sli关联到当前关联到当前Sale(形成关联)(形成关联)将将sli.quantity数值为数值为Quantity(修改属性)(修改属性)基于基于itemID的匹配,的匹配, 将将sli关联到关联到ProductSpecification(形成关联)(形成关联)选择控制类选择控制类 系统操作消息enterItem的责任的处理 如同makeNewSale一样,采用Controller 模式 继续使用Register 作为控制器是否要显示商品项目的描述和价格是否要显示商品项目的描述和价格 使用的设计原则被称为模型-视图分离

51、原则(Model-View Separation), 非GUI对象职责不应涉及输出任务。 尽管用例说明了在操作后描述和价格将被显示,但是设计中在此时将忽略此情况创建新的创建新的SalesLineItementerItem 契约的后置条件:显示创建,初始化和与SalesLineItem的关联 。 在领域模型中,Sale 包含了SaleLineItem对象。 因而,软件Sale 也类似地包含软件 SalesLineItem。 通过Creator模式, 发送makeLineItem消息到Sale来创建一个SaleLineItem。 makeLineItem 消息的参数包括Quantity。所以Sal

52、eLineItem可以记录此值, SaleLineItem也需记录与productDescription匹配的itemID值。寻找寻找ProductDescriptionSalesLineItem 要与匹配进入的要与匹配进入的itemID 的的ProductDescription 建立关联建立关联 这意味着基于一个这意味着基于一个itemID 匹配,必须返回一个匹配,必须返回一个 ProductDescription根据根据itemID的匹配,应该由谁负责了解的匹配,应该由谁负责了解ProductDescription No Creator模式模式 No Controller模式模式 信息专家

53、模式?信息专家模式? 信息专家模式:表明持有完成职责所需信息的对象应该负责上述职责。信息专家模式:表明持有完成职责所需信息的对象应该负责上述职责。 谁知道所有谁知道所有ProductDescription对象呢?对象呢? 依据领域模型,依据领域模型,ProductCatalog 逻辑上包含所有的逻辑上包含所有的ProductDescription. ProductCatalog是实现查找是实现查找ProductDescription职责的最佳候选者。职责的最佳候选者。 使用名为使用名为getProductDescription的方法实现这项查找工作。的方法实现这项查找工作。ProductCat

54、alog的可见性的可见性可见性可见性: 一个对象“看见”或引用另一个对象的能力如果某对象要发送消息到另一个对象时,它必须拥有对接如果某对象要发送消息到另一个对象时,它必须拥有对接收消息对象的可见性。收消息对象的可见性。谁应该发送谁应该发送getProductDescription消息给消息给ProductCategory来请求来请求ProductDescription呢?呢?假设在启动用例的初始过程中,创建假设在启动用例的初始过程中,创建长生命期长生命期的的Register和和ProductCategory实例,并且存在永久关联!实例,并且存在永久关联!Register拥有对拥有对Produc

55、tCategory的可见性,可以向它发送的可见性,可以向它发送getProductDescription的消息的消息enterItem最终设计最终设计协作图协作图enterItem最终设计最终设计类图类图SalesLineItemquantity : Integer.ProductCatalog.getProductDesc(.)ProductDescriptiondescription : Textprice : MoneyitemID: ItemID.1.*1.*Register.enterItem(.).SaleisComplete : Booleantime : DateTimemak

56、eLineItem(.).111catalogcurrentSaledescriptionsMaplineItemsordereddescription从数据库中检索从数据库中检索ProductDescription 不可能把所有不可能把所有 ProductDescription放在内存中。放在内存中。 但是可以把它们放在关系数据库或者对象数据库中,然后按需但是可以把它们放在关系数据库或者对象数据库中,然后按需检索检索 考虑到性能和容错,一些考虑到性能和容错,一些ProductDescription可以缓存在客可以缓存在客户端的进程中。户端的进程中。 为了简单起见,从数据库中检索的问题稍后讨论

57、,这里假设把为了简单起见,从数据库中检索的问题稍后讨论,这里假设把所有的所有的ProductDescription都装在内存里。都装在内存里。如何设计如何设计endSale 当收银员按下表示商品条目输入完毕的按钮后,将会产生endSale 系统操作选择控制类选择控制类 继续使用Register 作为控制器设置设置Sale.isComplete 属性属性 除非是控制器或者创建问题,否则信息专家模式应该是我们首先除非是控制器或者创建问题,否则信息专家模式应该是我们首先考虑的模式考虑的模式 谁应该负责将谁应该负责将Sale的属性的属性 isComplete 设置为设置为true呢呢? 根据信息专家模

58、式根据信息专家模式, 应该是由应该是由Sale 本身完成。本身完成。计算销售总额计算销售总额 依据模型视图分离的设计原则,我们现在依据模型视图分离的设计原则,我们现在不应该关注如何显不应该关注如何显示销售总额示销售总额,而是必须保证如何知道销售总额,而是必须保证如何知道销售总额 目前没有一个设计类知道销售总额,要设计对象的交互来满足目前没有一个设计类知道销售总额,要设计对象的交互来满足此需求。此需求。 除非是控制器或者创建问题,否则信息专家模式应该是我们首除非是控制器或者创建问题,否则信息专家模式应该是我们首先要考虑应用的模式先要考虑应用的模式分析过程:分析过程:1. 陈述职责:陈述职责:谁应

59、该负责了解销售总额?谁应该负责了解销售总额?2. 概括所需信息:概括所需信息:销售总额是所有销售条目的小计之和销售总额是所有销售条目的小计之和销售条目小计销售条目数量销售条目小计销售条目数量产品描述价格。产品描述价格。3. 列出实现此职责所需信息和了解这些信息的类。列出实现此职责所需信息和了解这些信息的类。销售总额所需要的信息销售总额所需要的信息信息专家信息专家ProductDescription.priceProductDescriptionSalesLineItem.quantitySalesLineItemAll the SalesLineItems in the current Sal

60、eSale 谁应该负责计算总额? 信息专家:因为Sale知道计算销售总额所必需的所有SaleLineItem实例,所以Sale将承担获知总额的职责。 销售条目小计? 信息专家:因为SaleLineItem知道其数量和与之关联的ProductDescription,所以SaleLineItem 承担获知小计的职责。 ProductionDescription价格? 信息专家: ProductionDescription自身,是它的一个属性。更详细的分析更详细的分析设计设计 Sale-getTotal 并不是每一个交互图都由系统操作消息并不是每一个交互图都由系统操作消息(如如enterItem或或

61、makeNewSale)开始,可以由设计者希望表示其交互的任何消息)开始,可以由设计者希望表示其交互的任何消息开始。开始。因为算法(通常)不是通过消息来说明的,那么可以通过在定义计算因为算法(通常)不是通过消息来说明的,那么可以通过在定义计算的图中附加算法或约束来阐述计算的细节的图中附加算法或约束来阐述计算的细节谁给谁给Sale发送发送getTotal消息呢?最有可能是消息呢?最有可能是UI层对象层对象如何设计如何设计makePayment 当收银员输入所支付的现金数额后,将发生 makePayment 系统操作创建创建Payment 创建了创建了Payment 的实例的实例p (创建实例创建

62、实例) 这是一个创建职责这是一个创建职责. 两个候选者两个候选者:Register 在实际领域中,正是在实际领域中,正是Register记录账户信息记录账户信息 Sale sale 对象频繁使用对象频繁使用Payment 应用信息专家模式:谁是与初始数据相关的信息专家?应用信息专家模式:谁是与初始数据相关的信息专家? Register是接收系统操作是接收系统操作makePayment消息消息 的控制器,最早持有收款总额的信息的控制器,最早持有收款总额的信息准则:准则:当存在多个可选设计时,应更深入地观察可选设计所存在的内聚和耦合,以及未来可能存在的进化压力。选择具有良好内聚,耦合和在未来变化时

63、能保持稳定的设计1: makePayment(cashTendered)1.1: create(cashTendered):Register:Sale:PaymentmakePayment(cashTendered) by Controllerby Creator and Low Coupling记录记录Sale的日志的日志如果采用后一种,如果采用后一种,SaleLedger还需要添加到领域模型中,它是现实领还需要添加到领域模型中,它是现实领域中的概念域中的概念专家模式:专家模式:谁负责获知所有已谁负责获知所有已记录的销售并完成记录的销售并完成日志记录工作?日志记录工作?1:Store2:财务

64、:财务SalesLedger假如坚持最初的计划而使用假如坚持最初的计划而使用Store计算余额计算余额 信息专家:谁负责获知支付余额呢?Payment :知道所支付的现金总额Sale:知道销售总额余额 =所支付的现金总额-销售总额 两个选择Payment: 它需要具有 Sale的可见性,以便向Sale 请求销售总额。它将增加整体设计的耦合度.Sale: 它需要具有Payment的可见性,由于它是创建者,已经拥有Payment的可见性。因此并不增加总的耦合s :Salepmt: Payment1: amt = getAmountbal = getBalance2: t = getTotal ba

65、l = pmt.amount - s.total S alesLineItemquantity : IntegergetS ubtotal()P roductC atalog.getP roductD esc(.)P roductD escriptiondescription : Textprice : M oneyitem ID : Item ID.S toreaddress : A ddressnam e : TextaddC om pleteS ale (.)P aym entam ount : M oney.1.*1.*R egister.endS ale()enterItem (.)

66、m akeN ew S ale ()m akeP aym ent(.)S aleisC om plete : B ooleantim e : D ateTim ebecom eC om plete ()m akeLineItem (.)m akeP aym ent(.)getTotal()111111*catalogcatalogregistercurrentS aledescriptionsM aplineItem sorderedpaym entcom pletedS alesordereddescriptionNextGen迭代迭代1最终的最终的DCD如何将如何将UI层连接到领域层层连接到领域层 常见设计: 从应用的起始方法(例如,Java的 main方法) 中调用的初始化对象,同时创建UI对象和领域对象,并且将领域对象传递给UI UI对象从众所周知的源提取领域对象,如一个负责创建领域对象的工厂对象第一种方法:第一种方法:在在Register中增加一个中增加一个getTotal方法,再委派给方法,再委派给Sale优点:低耦合(优点:低耦合(UI只知道只知道Register对象)对

展开阅读全文
温馨提示:
1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
2: 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
3.本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
关于我们 - 网站声明 - 网站地图 - 资源地图 - 友情链接 - 网站客服 - 联系我们

copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!