高级软件工程(第十一章)-面向对象设计方法(2017课件)

整理文档很辛苦,赏杯茶钱您下走!

免费阅读已结束,点击下载阅读编辑剩下 ...

阅读已结束,您可以下载文档离线阅读编辑

资源描述

11第十一章面向对象的设计方法面向对象设计的主要任务①细化重组类②细化和实现类间关系,明确其可见性③增加属性,指定属性的类型与可见性④分配职责,定义执行每个职责的方法⑤对消息驱动的系统,明确消息传递方式⑥利用设计模式进行局部设计⑦画出详细的类图与时序图233OO设计过程①基于领域模型,创建设计类图的基础版本或初步模型:包含属性名称等基本信息,以便用来设计交互图;②开发交互图,即为每一个用例产生一个交互图:其决定哪些对象一起工作,及怎样协同工作。(系统设计的核心);③根据开发交互图时得到的信息,迭代设计类图和开发方法名称(确定类的行为和职责)④用包图将设计类图分割成相关的功能。44用例的实现称设计模型的最终开发结果为用例的实现。术语实现指的是对每个用例的详细系统过程进行说明,是制定了软件的蓝图。OO的设计也是用例驱动的。也就是说,设计是由一个用例的实现接着一个用例的实现完成的。用例的实现:对每个用例的详细系统过程的说明。用例实现方案的步骤用例实现方案的设计方法有三个步骤:①提取边界类、实体类和控制类;②构造交互图;③根据交互图精化类图。566设计类图与领域模型设计类图和详细交互图均使用对方作为设计时的输入,二者的开发过程是平行的。设计类图是OO分析时开发的领域模型类图的扩展(分析阶段可忽略属性或方法)。领域模型揭示问题域类和它们之间的联系,是概念类模型。设计类图是领域模型的细化和扩展,是软件类模型。通过集成来自交互图和其他模型的信息来完成。设计类图时,还要在以前的领域模型的基础上增加很多类77标准设计类⑴实体类⑵边界类(接口类)⑶控制类88⑴实体类实体类:是问题域中的核心类。从客观世界中的实体对象归纳和抽象出来(来自域模型)。用于长期保存在系统中的信息以及提供针对这些信息的相关处理行为。实体类的对象是永久性的,即持久类。持久类:程序结束后仍然存在的对象类。在系统关闭后这些数据仍存在。保证持久的方法:将它们写入文件或DB。实体类在DB中有相应的表,其属性对应DB中的字段。续实体类表示目标软件系统中具有持久意义的信息项及其操作。实体类的操作具有“内向收敛”特征,它们仅向目标软件系统的其余部分提供读、写信息项内容的必要的操作接口,并不涉及业务逻辑处理。91010⑵边界类(接口类)从系统和外界进行交互的对象中归纳、抽象出来。是系统内对象和系统外的参与者的联系媒介,外界消息通过边界类的对象实例发送给系统。(例如,窗体、对话框、报表)边界类:存在于系统的自动化边界上的类。续边界类描述目标软件系统与外部环境的交互,主要任务:1.界面控制:包括输入数据的格式及内容转换,输出结果的呈现,软件运行过程中界面的变化与切换等。2.外部接口:实现目标软件系统与外部系统或外部设备之间的信息交流和互操作。主要关注跨越目标软件系统边界的通信协议。3.环境隔离:将目标软件系统与操作系统、数据库管理系统、应用服务器中间件等环境软件进行交互的功能与特性封装于边界类之中,使目标软件系统的其余部分尽可能地独立于环境软件。111212⑶控制类控制类:在边界类和实体类中间起协调作用的类,它包含了事件的应用逻辑或业务规则。它负责从边界类对象获取信息,然后发送到适当的实体类对象,就像是域层和可视层之间的一个控制器。在一个用例中,一个控制类应该同一个且仅一个参与者相关联。协调边界类和实体类之间的消息及消息发送的顺序。续控制类作为完成用例任务的责任承担者,协调、控制其他类共同完成用例规定的功能或行为。对于比较复杂的用例,控制类通常并不处理具体的任务细节,但是它应知道如何分解任务,如何将子任务分派给适当的辅助类,如何在辅助类之间进行消息传递和协调。13提取边界类、实体类和控制类如何从分析模型中的用例描述和领域概念模型出发获取这些类?通常情况下,参与者与用例之间的一种通信连接对应一个边界类。但是,如果两个以上的用例与同一参与者交互,并且这些交互具有共同的行为、完成相同或类似的任务,就可以考虑用同一边界类实现用例与参与者之间的交互。这就意味着边界类的作用范围可以超越单个用例。14提取边界类、实体类和控制类实体类源于领域模型。有时也需要认真研读用例描述,从中发掘具有持久意义的信息项。如果参与者的属性需要持久保存,也可以建立相应于执行者的实体类。假设一个实体类A仅仅被系统中的另一个类B引用,并且系统勿需关心A的行为特征,那么,为了简化设计模型,应将A中信息项直接作为B的属性。如果A被系统中的多个类引用,或者A具有不容忽略的行为特征,那么应将A作为独立的实体类。15提取边界类、实体类和控制类一个用例通常对应一个控制类。如果不同用例的任务有较多类似之处,也可以考虑在多个用例的实现方案中共享同一控制类,此种情况应审慎对待,不同用例所需要的控制、协调行为往往会有差异。对于那些事件流非常简单的用例,可以不设独立的控制类,直接在边界类中设置控制、协调功能,边界类在实体类的帮助下完成用例要求的功能及行为。1617导航可见性一个对象可看到另一个对象并与之交互(导航、可见性)。一个对象可导航(发送消息)到另一个对象。一个对象通过发消息的方式和另一个对象进行联系,那么第二个对象对于第一个对象来说必须是可见的。对象具有能看见另一对象并与其交互的能力。1818用例实现与交互图用例的实现是在交互图的开发过程中完成的,用例实现的过程就是确定哪些类通过发送消息与其他类进行协作的过程。设计时开发的交互图:顺序图或协作图。1919对象职责一种由对象负责实施系统过程的设计准则。集中确定一个系统必须支持的行为,再设计实现这些行为的方法。通过这些行为,确定对象职责。2020用例控制器每个用例含有许多来自外部参与者不同的消息。作为OO分析一部分的系统顺序图能够描述出这些输入消息,但只表示这些消息输入到系统中。在设计过程中,必须确定对象得到所有的消息。为简化搜集和处理用例所需要的全部消息的过程,系统设计者通常建立一个新类,该类用做输入消息的采集点,称其为用例控制器。构造交互图在标识边界类、实体类和控制类之后,接下来的任务是,将分析模型中的用例描述转化成UML交互图,以交互图作为用例的详细实现方案。用例描述中事件流说明中的事件应直接对应于交互图中的消息,而事件间的先后关系体现为交互图中的时序,对消息的响应则构成消息接收者的职责。这种职责在后续的设计活动中将被确立为类的方法。212222顺序图初步设计的规则接受每个输入消息并确定由这个输入消息产生的所有的内部消息。在处理每个消息的时候,一定要辨别出受之影响的类的完整集合,即从领域类图中找到需要的所有对象。充实消息的结构。添加迭代、真/假条件、返回值和传递参数。构造顺序图控制类或辅助类可以向右侧的边界类发送消息,将消息或外部处理请求由边界类传向外部系统(被动执行者)。在用例描述中,许多用例除主事件流外,往往还包含备选事件流,以说明在某些特殊或者异常情况下的事件和响应动作序列。为易于理解,在设计模型中应该用分离的UML交互图分别表示事件流和每个备选事件流。23精化类图在UML交互图中,对每个类的对象都规定了它必须响应的消息以及类的对象之间的消息传递通道。前者对应于类的操作,后者则对应于类之间的连接关系。因此,可以利用交互图精化分析模型中的类图,将交互图中出现的新类添加到原有类图中,并且对相关的类进行精化,定义其属性和操作。原则上,每个类都应该有一个操作来响应交互图中指向其对象的那条消息。但是,这并不意味着消息与操作一定会一一对应,因为类的一个操作可能具有响应多条消息的能力。同理,两个类之间的一条连接关系也可以为多条消息提供传递通道。为了简化设计模型,也为了提高重用程度,设计人员应该尽量使用已有的操作来响应新消息,并尽量使用已存在的连接路径作为消息传递的通道。如果两个类之间存在明确、自然的聚合或组合关系,则可以在类图中直接用相应的UML图元符号表示类间的聚合和组成关系,这两个关系均可提供消息传递通道。24系统中的每一个对象都应该只有一个单独的职责,而任何对象所关注的就是自身职责的完成。合适的行为应该出现在合适的类里。一个类承担的职责越多,它被复用的可能性越小。类的职责主要包括两个方面:数据职责和行为职责,数据职责通过其属性来体现,而行为职责通过其方法来体现。单一职责原则是实现高内聚、低耦合的指导方针,在很多代码重构手法中都能找到它的存在,它是最简单但又最难运用的原则,需要设计人员发现类的不同职责并将其分离,而发现类的多重职责需要设计人员具有较强的分析设计能力和相关重构经验。25单一职责原则(SRP)开闭原则(OCP)一个软件实体应当对扩展开放,对修改关闭。也就是说在设计一个模块的时候,应当使这个模块可以在不被修改的前提下被扩展,即实现在不修改源代码的情况下改变这个模块的行为。“不能修改而可以扩展”是不允许更改系统的抽象层,而允许扩展的是系统的实现层。如何做到既不修改,又可以扩展?抽象化是开闭原则的关键。让模块依赖于一个固定的抽象体,这样它就是不可以修改的;同时,通过这个抽象体派生,就可以扩展此模块的行为功能。这样设计的程序只通过增加代码来变化而不是通过更改现有代码来变化。26里氏代换原则可以通俗表述为:在软件中如果能够使用基类对象,那么一定能够使用其子类对象。把基类都替换成它的子类,程序将不会产生任何错误和异常,反过来则不成立,如果一个软件实体使用的是一个子类的话,那么它不一定能够使用基类。里氏代换原则是实现开闭原则的重要方式之一,由于使用基类对象的地方都可以使用子类对象,因此在程序中尽量使用基类类型来对对象进行定义,而在运行时再确定其子类类型,用子类对象来替换父类对象。27里氏(Liskov)替换原则(LSP)依赖倒置原则(DIP)高层模块不应该依赖于低层模块,二者都应该依赖于抽象。抽象不应该依赖于实现细节,实现细节应该依赖于抽象。依赖倒转原则的常用实现方式之一是在代码中使用抽象类,而将具体类放在配置文件中。依赖倒置原则指依赖关系应该是尽量依赖接口或抽象类,而不是依赖于具体类。要针对接口或抽象类编程,而不是针对具体类编程。28接口分离原则接口分离原则指的是在设计时采用多个与特定客户类有关的接口比采用一个通用接口更好。也就是说一个类如果要被多个客户类使用,那么可以给每一个客户类创建一个接口,同时用这个类实现所有接口。不要在一个接口中包含所有客户类需要的方法。客户端不应该依赖那些它不需要的接口。一旦一个接口太大,则需要将它分割成一些更细小的接口,使用该接口的客户端仅需知道与之相关的方法即可。2930课堂复习1.在面向对象设计中使用哪三种基本设计类?简述这三种基本设计类。2.什么是导航可见性?举例说明。在编程中是如何实现的?开闭原则练习下图是一个针对不同打印机实现打印功能的类图设计,根据图中设计,如果现在需要添加一台Legend打印机,需做哪些修改?上图设计并不合理,因为如果需要新加一台新的Legend打印机的话,不但要增加一个新的Legend类,还要修改Output类的内部结构。不符合开闭原则。那么,应该如何改进呢?31上图中引入了一个接口类Printer,其中有一个print()方法。Output类只与这个接口类相关联,在Output类中有一个类型为Printer的变量p。不管系统与哪种打印机连接,实现打印功能时一律调用p.print()方法。而p的具体类型在运行是由系统确定,可能是HP类型的对象,也可能是Canon类型的对象。现在如果系统需要加入Legend打印机,只需增加一个Legend类,并在该类中实现Printer接口即可。因此,上图具有良好的可扩展性,符合开闭原则。32Class2Class1Class3Class4图1中Class4同时被Class1,2,3调用,是一种不好的设计,应该怎样改进?Class4Class2Interface2InterfaceClass3Interface3InterfaceCl

1 / 33
下载文档,编辑使用

©2015-2020 m.777doc.com 三七文档.

备案号:鲁ICP备2024069028号-1 客服联系 QQ:2149211541

×
保存成功