软件工程教案(理论课程)_第1页
软件工程教案(理论课程)_第2页
软件工程教案(理论课程)_第3页
软件工程教案(理论课程)_第4页
软件工程教案(理论课程)_第5页
已阅读5页,还剩88页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

PAGEPAGE4教师备课教案本(理论课程)系别:计算机工程系课程名称:软件工程教师姓名:段琢华授课时间:2013-2014学年第2学期电子科技大学中山学院

教师授课计划*课程名称软件工程学分3课程类型1、普通教育必修课();2、学科基础必修课();3、专业方向课(√);4、学科基础选修课();5、素质教育选修课();6、专业选修课()。学时分配总学时:48;课堂讲授:32学时;实践(验)课16学时授课起止周1-16授课班级游戏11,嵌入式11,网络11班级人数56,69,50授课总次数*16教材名称《软件工程案例教程:软件项目开发实践第2版》作者韩万江姜立新出版时间2011年10月13日章节基本内容计划学时1软件工程总揽(软件工程知识体系,软件工程的三段论,方法、过程和工具的概述)62软件开发模型及可行性研究2软件需求(需求定义,需求层次,需求建模,需求规格说明,需求验证和变更控制)43分析建模(领域建模,架构设计)44软件设计(设计模式的应用,子系统设计)86软件编码(编码方法,编码过程)47软件测试、发布与维护(测试方法,测试级别)4考核要求(根据课程实际情况,不做要求的项目可不写):1、平时成绩的构成比例和考核方式;20%考勤和读书笔记2、期中成绩的构成比例和考核方式;3、期末成绩的构成比例和考核方式;50%综合课程设计4、实验成绩的构成比例和考核方式。30%上机实验。填表日期:2014年教学后记**“教学后记”是授课完毕之后,教师对授课准备情况、授课过程及授课效果的回顾与总结,因此,教师应及时手写补充完整本部分内容。时间安排第周,总第次课章节名称需求工程(4次课)教学目的需求的定义和需求的层次。什么是用例,如何编写用例。如何构建需求模型,如何编写需求规格说明书。教学重点与难点1、需求捕获的方法。2、用例。3、需求模型的构建。4、需求规格说明书的编写。教学内容与过程设计教学内容与过程设计启动软件项目是由于软件需求的存在,资料表明,软件项目中40%~60%的问题都是在需求分析阶段埋下的隐患。软件开发中返工开销占开发总费用的40%,而其中70%~80%的返工是由需求方面的错误所导致。因此一个项目成功的关键因素之一就是对需求分析的把握程度。而项目的整体风险往往表现在需求分析不明确,业务流程不合理,所以,需求分析是软件开发的重要一环。软件的需求具有模糊性、不确定性、变化性和主观性的特点,相比硬件的需求,是有形的、客观的、可描述的、可检测的。一、需求的定义需求,是指对用户需要解决的问题的整体描述。需求是软件实现之源,没有了需求,软件也就无从谈起。在IEEE软件工程标准词汇表中定义需求为:(1)用户解决问题或达到目标所需要的条件或能力(2)系统或系统部件要满足合同、标准、规范或其他正式规定文档所需具有的条件或能力(3)一种反映上面(1)或(2)所描述条件或能力的文档说明二、需求的层次软件需求是指用户对软件的功能和性能的要求。软件人员要准确理解用户的要求,进行细致的调查分析,将用户非形式化的需求陈述转化为完整的需求定义,再由需求定义转化到相应形式的需求规格说明。有时也可以将软件需求按照层次来说明(如上图)。业务需求:反映了组织机构或客户对系统、产品高层次的目标要求,它们在项目视图与范围文档中说明。用户需求:用户使用产品必须要完成的任务,它们通常使用用例文档(usecase)进行说明。功能需求:开发人员必须实现的软件功能,使得用户能完成他们的任务,从而满足了业务需求。非功能需求:描述系统展现给用户的行为和执行的操作等。包括:产品必须遵循的标准、规范和合约;外部界面的具体细节;性能要求;设计或实现的约束条件;质量属性。通常也可以总结为FURPS+:Functional(功能性):特性、功能、安全性。Usability(可用性):人性化因素、帮助、文档。Reliability(可靠性):故障频率、可恢复性、可预测性。Performance(性能):响应时间、吞吐量、准确性、有效性、资源利用率。Supportability(可支持性):适应性、可维护性、国际化、可配置性。+:表示一些辅助性的和次要的因素,比如:实现(Implementation):资源限制、语言和工具、硬件等。接口(Interface):强加于外部系统接口之上的约束。操作(Operation):对其操作设置的系统管理。包装(Packaging):例如物理的包装盒。授权(Legal):许可证或其他方式。软件需求规格:软件需求规格充分描述了软件系统应具有的外部行为,它描述了系统展现给用户的行为和执行的操作等。它包括产品必须遵从的标准、规范和合约;外部界面的具体细节;非功能性需求(例如性能要求等);设计或实现的约束条件及质量属性。软件需求规格说明在开发、测试、质量保证、项目管理以及相关项目功能中都起到重要的作用。为了强调非功能需求,举例说明:2月27日,中央电视台“第一时间”报道了北京市二中院开庭审理程稚瀚涉嫌盗取北京移动通信公司充值卡密码一案,程稚瀚曾是UT斯达康深圳分公司工程师,被指控利用网络技术手段侵入北京移动通信公司充值中心数据库,修改充值卡原始数据并窃取了充值卡密码,并通过淘宝网和QQ向他人出售,致使北京移动通信公司损失近380万元。该栏目主持人认为:1.2亿元网络安全投入,居然不堪一击,中国移动也该好好总结一下了。事实上,程稚瀚在作案过程中使用的大多都是些没有技术含量的攻击手段,但是偏偏没有技术含量的攻击事件,在电信、银行、证券、保险业却屡屡得逞另一个案例:两大学生利用网通ADSL用户升级时系统的漏洞,在一个月内盗取了价值70余万元的网易一卡通虚拟游戏点卡。不能不令我们深思。三分技术,七分管理”的网络安全体系建立原则几乎被每个电信和银行业的企业所强调,并成为指导其安全管理体系建设的基本原则。三、需求工程20世纪80年代中期,形成了软件工程的子领域——需求工程。需求工程是指应用已证实有效的技术、方法进行需求分析,确定客户需求,帮助分析人员理解问题并定义目标系统的所有外部特征的一门学科。四、需求问题的代价在早期阶段,软件是无形的,除了一些文档性的规格说明以外没有什么具体有形的东西,而且比较容易修改。但随着时间的推移,软件产品越来越详细(在设计阶段),越来越具体(在编码阶段),越来越固定(当代码逐渐接近最终的方案时)。在早期可以轻易改变的东西,越到后期就越难得多。很多人不理解这些前期准备的重要性,其实我们可以把软件过程比作食物链。其中程序员是软件食物链的最后一环。架构师吃掉需求,设计师吃掉架构,而程序员则消化设计。在健康的生态环境中,海鸥吃新鲜的鲑鱼。这对海鸥是营养丰富的大餐,因为鲑鱼吃的是新鲜的青鱼,而青鱼吃的是新鲜的水蝽。这是一条健康的食物链。在软件开发中如果食物链的每一级都是健康的食物,那么最终由程序员编写出的代码也是健康的。而在受污染的环境中,水蝽在核废料中游泳,青鱼被聚氯联二苯污染,而吃青鱼的鲑鱼又在泄漏的原油中游荡。海鸥,就成为最不幸的了,因此它吃下去的不仅仅是不健康的鲑鱼体内的原油,还有青鱼体内的聚氯联二苯和水蝽体内的核废料。在软件开发中,如果需求污染了,它就会污染架构,而架构就会污染编码。这样会导致程序员脾气暴躁、营养失调;开发出的软件具有放射性污染,而且周身都是缺陷。五、需求面临的困难“石头”问题:说客户常常会交给她一些项目,她称之为“给我一块石头”。可是当你把石头交给客户时,他会看一会“石头”,然后说:“是的,但是……,实际上我想要的是一块小一点的蓝色石头。”而当你交出一块小一点的蓝色石头时,又会引发“一块圆的小一点的蓝色石头”的要求。最终的结果可能是,客户一直都在想要一块小一点的蓝色大理石—或者他也许根本不能确定他到底要什么,而不是一块小小的蓝色大理石—甚至是猫眼大小的蓝色大理石就已经足够了。而他会在你交出第一块(大的)石头和第三块(蓝色的小)石子之间不断改变对需求的想法。开发人员在与客户会谈时总会提这样的问题:“你想要它做什么?”当开发人员按照客户预先的需求经过艰苦努力终于交出一块石头却得不到客户的肯定时,总是感到非常沮丧;而客户也同样沮丧,因为即使他可能也发现很难说清自己真正的要求,他还是觉得自己已经讲得很明白,只是开发人员没理解罢了!解决需求问题的手段和方法:A、分离稳定和不稳定B、先定架构再进行子系统的开发六、什么是用例用例:一种被广泛使用的用于发现和记录需求的机制。用例就是如何使用系统来达到目标的一组情节。用例不应该被设计得过于复杂,写到够用的详细程度即可。一个用例就是描述参与者使用系统来达成目标的时候一组相关的成功场景和失败场景的集合。用例是文本文档而不是图表,用例建模的主要工作是写文本而不是画图。用例的层次性使得用例对需求变更的适应性很强。再次强调:用例是文本形式的情节描述,用以说明某参与者使用系统以实现某些目标。初学者的常见错误就是注重于次要的UML用例图,而非重要的用例文本。七、需求调研需求获取的主要任务是和用户方的领导层、业务层人员的访谈式沟通,目的是从宏观上把握用户的具体需求方向和趋势,了解现有的组织架构、业务流程、硬件环境、软件环境、现有的运行系统等具体情况和客观的信息,以建立起良好的沟通渠道和方式。需求调研的方式(1)访谈和会议:需要注意,每一次交流一定要有记录,对于交流的结果还可以进行分类,便于后续的分析活动。例如,可以将需求细分为功能需求、非功能需求、环境限制、设计约束等类型。(2)市场调查(3)访问用户和用户领域的专家(4)考察现场,跟踪现场业务流程(5)开发人员和用户共同组成联合小组“老太太哲学”来源于李瑞环在天津当市长时候的一个故事,说是,人大代表、政协委员和各界群众座谈,有一次,一个老太太问:她家的煤气灶为什么总是点不着火?主管领导通过讲道理、摆数字的方式,给老太太解释,此时李瑞环说,你不用讲太多道理,老太太只要求煤气能一点就着。

许多媒体用“老百姓哲学”来对这个故事进行解读,说是政府要替老百姓办实事。我这里从软件工程的角度解读一下。

老太太提问题的目的,显然不是为了学习煤气灶点火的机理,实际上传递了一个信息,天津的煤气有问题,点不着。政府官员,假定不是推卸责任的话,显然没有理解老太太的真实意图。官员的回答,也没有用老太太能理解的方式进行,他应该直接告诉老太太怎么做,即便要推卸责任,用哪些情况做不到来代替说理也要好些。

软件工程中,需求获取是项目的重要步骤,用户的问题域是项目执行者要解决的目标域,不过,这两个域却存在不同的表达方式,用户总是从使用的角度来理解问题和提出问题,项目人员总是从设计的角度来理解问题和解决问题。

客户的问题并不能直接变成项目执行的目标,因为客户的问题使用业务术语来描述,项目却需要软件术语来执行。举例子说,数学工作者的问题是用数学公式来描述的,他并不知道软件怎样设计才能完成他的任务,如果软件设计者只熟悉软件领域,数学公式他也无法看懂,就谈不上完成任务。

需求问题实际上还要复杂,客户受限于知识水平和经验,常常无法准确地表达要求,作为问题提出者,他们的描述是零散的、模糊的、错误的甚至是自相矛盾的,而这样的目标无法完成,因此,需求获取者从有干扰的信息中挖掘、过滤、还原用户的真实需求,是重要的任务。

要准确获取需求,需要贴近客户,用他们能够理解的方式沟通,说他们能够听得懂的话,而不是鸡对鸭讲,各说各话。对于技术人员之间,则要用技术人员的语言,便于意思的精确表达,减少交流误差。表现在软件工程中,就是对不同的人建立不同的模型。不同的模型分别以不同的侧面来展现问题本身。

如果你是技术人员,你不能很好的和客户沟通,或者你的老板总是不理解你每天的辛苦,老太太哲学应该能给你一些提示。调研中存在的问题小型项目:投入几万到三四十万的项目,忽略合同或协议的签署,而仅仅只有一个表面的意向。最终导致在开发过程中,用户不断提出各种各样的问题和要求,以至于需求工作无法正常进行。大型项目:几百万或者几千万的项目。软件开发商急切的想得到这个项目,于是就逼迫开发人员尽快投入开发,必须不惜一切代价去拿下它。这样也就直接造成在还没有签订合同和正式协议之前,开发人员就不得不进入用户的工作区进行需求调研。此时,如果商务最终没有能谈下来,就使得开发人员的工作付之东流。用户日渐成熟:用户会要求软件厂商先拿出相应的产品或者软件,然后才会考虑和软件厂商签订进一步合同。用户甚至希望,先试用软件(其实是使用软件),然后签合同。合同一旦签完,软件就可全部交付!而国内软件企业很难做到(产品化的软件太少,造成经常发生用户现场定制开发工作的情况存在。)用户过于繁忙:用户有很多借口说忙。当然,在需求调研人员以诸如请客吃饭为借口搞好关系的时候,他们大多数还是愿意来的。因此需求调研人员就需要考虑如何协调这其中的关系,来保证需求调研的顺利完成。这时需要掌握好一个原则是:不能逼迫用户(如催促等行为),不要以与项目相关的任何理由来逼迫用户配合需求调研工作。不同的软件不同的结果:对于可以让客户直接见到利益的软件系统,用户愿意购买,也比较愿意付款,而且也比较愿意配合您的工作。但是这样的项目大部分都隶属于增值业务范围之内。还有相当数量的软件是不可能让客户直接体会到收益的;此时应该注意将隐藏在软件产品后面的收益尽量呈献出来,让客户充分体会到。高层的关注:高层领导非常关注的大型项目,一般比较容易推进。例如电信行业的计费、网管系统,税务的税收、缴费系统、电力的生产、调度、计费、电检系统等。但是,也要注意,不要因为引起了高层的关注就对下面的人不再关注,更不能因此而引起具体办事人员的反感,否则将使项目的进展面临异乎寻常的压力。和用户交流的技巧交流中的心态定位:首先,开发人员一定要让用户意识到:开发人员是为他们工作的!开发人员的工作不会造成他们被裁掉,只是用来简化他们的工作,减轻他们的工作负担,让他们可以更舒服、更轻松地工作——即使,最终的结果可能完全相反,也要如此做。我们要为用户考虑:应该站在用户的立场上进行考虑。采用适当的交流语言:尽量采用用户行业内的语言或者用户可以理解的语言和方式。使用流程图最常用的方式是:用户边描述,需求人员边绘图,然后给用户看图,让用户根据图来指出问题,然后,再修改,再看,如此反复,直到用户满意为止。表格:流程图可以描述工作流程,而表格可以描述工作的结果,或者阶段性成果。图形:如设备部署图、网络结构图、资源分布图等。文字:使用文字是必须的,但是文字越少越好!描述性文字一定要精练、短小,切忌长篇大论。八、需求建模问题的提出:在系统尚未存在时,怎样描述用户需要一个什么样的系统?如何规范的定义用户需求?考虑问题的思路:把系统看作一个黑箱,看它对外部的客观世界发挥什么作用,描述它外部可见的行为。注意:需求是技术无关的。在需求阶段讨论技术是没有任何意义的。那只会让你的注意力分散。需求分析的基本策略是采用脑力风暴、专家评审、焦点会议组等方式进行具体的流程细化、数据项的确认,必要时可以提供原型系统和明确的业务流程报告、数据项表,并能清晰地向用户描述系统的业务流设计目标。用户方可以通过审查业务流程报告、数据项表以及操作开发方提供的原型系统,来提出反馈意见,并对可接受的报告、文档签字确认。需求建模的步骤:1、识别执行者2、识别用例3、详述业务用例4、对用例进行排序和分包第一步:识别执行者执行者:在系统之外,透过系统边界与系统进行有意义交互的任何人或外部系统。三类参与者:1、主要参与者:具有用户目标,并通过使用该系统的服务完成。为何确定主要参与者?发现驱动用例的用户目标。2、协助参与者:为系统提供服务(例如,信息服务)。自动付费授权服务即是一例。协助参与者通常是计算机系统,但也可以是组织和人。为何确定协助参与者?为了明确外部接口和协议。3、幕后参与者:在用例行为中具有影响或利益,但不是主要或协助参与者。例如,政府税收机构。为何确定幕后参与者?这是为了确保确定并满足所有必要的重要事物。如果不明确地对幕后参与者进行命名,则有时很容易忽略其影响或利益。执行者要点:系统外—必须和它交互系统边界--责任边界,非物理边界系统边界--直接与系统交互有意义交互--属于目标系统的责任任何事物--人、外系统、外部因素、时间与外部系统交互的几种情况:1、一直与系统进行交互的其他系统或设备。2、发起交互的其他系统或设备。3、从交互中取值的其他系统或设备。注意:用例图的执行者描述了可以由某些实体扮演的一种角色,不表示一个特定个体。一个执行者和一个用例之间存在通信关系并不意味着扮演这个角色的实体必须执行某个任务,它仅表示可能执行这个任务,这取决于具体情况。第二步:识别用例用例实例是在系统中执行的一系列动作,这些动作将生成特定执行者可见的价值结果。一个用例定义一组用例实例。用例的三种常用形式:1、摘要——简洁的一段式概要,通常用于主成功场景。何时使用?在早期需求分析过程中,为快速了解主题和范围。可能只需要几分钟进行编写。2、非正式——非正式的段落格式。用几个段落覆盖不同场景。何时使用?同上。3、详述——详细编写所有步骤及各种变化,同时具有补充部分,如前置条件和成功保证。何时使用?确定并以摘要形式编写了大量用例后,在第一次需求讨论会中,详细地编写其中少量(10%)的具有重要架构意义和高价值的用例。识别用例的要点:价值结果à有意义的目标执行者可见à业务语言执行者可见à用户观点一组用例实例à用例的粒度用例的粒度讨论:警惕CRUD泛滥!Create,Read,update,delete用有色眼镜看,所有业务最终都会成为CRUD多问:为什么要CRUD?光CRUD能为actor提供价值吗?如果CRUD不涉及复杂的交互,一个用例“管理××”即可不管是C、R、U、D,都是为了完成“管理”的目标甚至很多种基本数据的管理都可以用一个用例表示讨论:登陆怎么处理方案二:“登陆”用例仅描述登陆的信息,会员执行其他功能时都要先登陆,其缺点为,对会员要进行多次验证。方案三:注意在“购物”和“修改会员资料”用例的前置条件中写明登陆成功条件。用例的关系:扩展关系:扩展关系允许一个用例(可选)扩展另一个用例(基用例)提供的功能。注意扩展只能在特定的设计点发生,称这个点为扩展点(通常为测试条件点,行为在该点开始分支)。基用例路径本身是完整的,原来可能是一条扩展路径。寻找用例中的特殊场景:用例中的特殊场景点,(例如,购物,包括支付卡,现金,优惠卷等),(例如,定价,包括打折的业务规则)。包含关系:何时使用包含关系:某些步骤在多个用例重复出现,且单独形成价值,即用例之间的公共功能。已经有现成的公共用例存在,只需拿来使用即可。用例的步骤较多时,可以用Include简化(慎用)泛化关系:用例之间的泛化:一个任务与该任务的一个特殊版本之间的关系。例子:在买票系统中,个人购买和团体购买都是买票的特例。采用关系不同,文档结构不同(如果改成extend,则表示识别用户用例中的另外一条路径)讨论:泛化与扩展的区别如果打算描述一个根据“运行时”条件有可能在某一时刻增加的附加行为,则可以使用扩展。如果希望标记整个任务的一个特定版本,就应该用泛化。第三步:编写用例文档用例文档模板:用例编号:用例名执行者前置条件后置条件涉众利益基本路径1…..××××2……××××3…..××××扩展2a.××××:2a1….×××××字段列表业务规则非功能需求设计约束待解决问题前置条件和后置条件:开始用例之前必须满足的条件。注意:必须是系统能检测的。用例成功结束后系统应该具备的状态。例如,前提条件可能是另一个用例已经执行,或者用户具有运行当前用例的权限。用例图并不显示用例执行的顺序,但前提条件可以将这一方面的信息建档。前置条件传达的是编写者认为应该引起读者警惕的那些值得注意的假设。涉众利益:回答了用例应该包含什么?即用例应该包含满足了所有项目相关人员兴趣的内容。另外,在编写用例其余部分之前就确定涉众及其关注点,能够让我们更加清楚地了解详细的系统职责。基本路径:核心的核心:客户最想看到、最关心的路径路径交互步骤的描述方法:只书写“可观测”的(说人话)使用主动语句句子必须以执行者或系统作为主语每一句都要朝目标迈进分支和循环不要涉及界面细节各种补充约束的描述方法:非功能性需求:正确性:correctness,指系统规范、设计和实现方面的错误的稀少程度。可用性:指用户学习和使用一个系统的容易程度。高可用性是评价服务质量的重要依据之一,在通常情况下,达到高可用性需要高昂的代价。例如:可用性比例平均年停机时间98%7.3天99%87.6小时99.5%43.8小时99.9%8.76小时99.95%4.38小时99.99%53分钟99.999%5.25分钟99.9999%31秒99.99999%3.1秒集群是一种廉价且实用的高可用性解决方案。所谓集群指的是一系列节点的集合,这些节点具有相同的目的,并且互相连接。集群的优点在于可以赋予服务容错和负载均衡的能力。集群通过多个节点间的相互补充,可以在其中某个节点失效时持续的提供服务,从而提高服务的可用性;通过集群中各节点对负载的动态分担,可以将负载比较均匀的分布到多个节点中,从而提高整体性能。可靠性:Reliability,指在指定的必需条件下,一个系统完成所需功能的能力——应该有很长的平均无故障时间。数据库服务器+备份服务器各种设计约束:界面样式:系统显示订单明细,应采用附件××所示的屏幕格式报表:系统打印工资单,工资单的格式如附件××所示平台:一般针对整个系统:由于公司目前大约有200台PC在使用,还需要使用若干年,所以系统应能在这些PC上运行(Pentium166,128MRAM)由于×公司的IT人员有Oracle专长,而且目前已有的其他应用系统也使用Oracle数据库,所以系统应使用Oracle数据库。接口:通过RS-232接口读取。总结:用例编写准则1、以无用户界面约束的本质风格编写用例。2、编写简洁的用例。3、编写黑盒用例。(黑盒用例不对系统内部工作、构件或设计进行描述。反之,它以通过职责来描述系统)4、采用参与者和参与者目标的视点。第四步:对用例进行排序和分包排序原则:以下情况的用例优先级别最高a)对类图有重要影响b)包含丰富的业务过程信息和线索c)有开发风险、时间紧迫或功能复杂d)涉及到重要核心技术或新技术e)能直接产生经济效益或降低成本f)代表本系统的核心流程分包原则:按执行者分包按主题分包按开发团队分包按发布情况分包补充、活动图利用文本描述事件流是很有用的,但如果事件流的逻辑复杂且有许多其他事件流,则文本形式可能较难阅读和理解。这时可以使用活动图来描述事件流,它是事件流的另一种建模方式。在用例模型中,活动图用来捕捉用例的活动,它着重描述操作以及用例实例或对象中的活动。活动图是一种描述工作流的方式,它用来描述采取何种动作、做什么(对象状态改变)、何时发生(动作序列)以及在何处发生(泳道)。活动图用于描述系统的工作流程和并发行为,活动图可以看作状态图的特殊形式,活动图中一个活动结束后将立即进入下一个活动。总结:用例实践方法最理想:客户写用例--理想即不现实最糟糕:客户不参与,开发人员杜撰折衷:客户提供素材,开发人员写用例九、需求管理由于需求是正在构建的系统必须符合的事务,而且符合某些需求决定了项目的成功或失败,因此找出需求是什么,将它们记下来,进行组织,并在发生变化时对它们进行追踪,这些活动都是有意义的。需求管理就是:一种获取、组织并记录系统需求的系统化方案,以及一个使客户与项目团队对不断变更的系统需求达成并保持一致的过程。需求管理的主要活动:需求确认:开发方和客户共同对需求文档进行评审,双方对需求达成共识后做出书面承诺,使需求文档具有商业合同效果。在设计开始之前验证需求的正确性及其质量,就能大大减少项目后期的返工现象。需求验证务必确保需求符合完整性、正确性、灵活性、必要性、无二义性、一致性、可跟踪性及可验证性等。需求跟踪:将系统设计、编程、测试等阶段的工作成果与需求文档进行比较,建立与维护“需求文档-设计文档-代码-测试用例”之间的一致性,确保产品依据需求文档进行开发。需求变更控制:依据“变更申请——审批——更改——重新确认”的流程处理需求的变更,确保需求的变更不会失去控制而导致项目发生混乱。这是一句老话了:唯一不变的只有变化。你应该将所有系统将可能发生的变化以及潜在需求记录下来,以便将来能够实现通过在建模期间考虑这些假设的情况,你就有可能开发出足够强壮且容易维护的软件。设计强壮的软件是你最基本的目标。案例分析:某公司的需求变更控制流程教学后记**“教学后记”是授课完毕之后,教师对授课准备情况、授课过程及授课效果的回顾与总结,因此,教师应及时手写补充完整本部分内容。时间安排4次课章节名称面向对象分析教学目的掌握分析阶段的主要活动掌握领域建模、系统顺序图、操作契约等的编写方法教学重点与难点静态模型的建模方法动态模型的建模方法教学内容与过程设计教学内容与过程设计一、概述OOA:概念层。帮助软件工程人员和用户组织目标系统的知识。不考虑与实现有关的因素。是一种以从问题域词汇中发现的类和对象的概念来考察需求的分析方法。OOD:OOD把注意的焦点从问题空间转移到了解空间。针对系统的具体实现,对OOA阶段建立的模型进行调整与增补,并对人机界面、数据存储和控制接口建模。OOP:实现层,把OOD模型变为程序。即用面向对象语言(如C++,Java等)实现设计。分析和设计可以概括为:做正确的事(分析)和正确地做事(设计)。面向对象分析和设计:在OOA过程中,强调的是在问题领域内发现和描述对象或概念。在OOD过程中,强调的是定义软件对象和这些软件对象如何协作来满足需求。UP过程的描述:初始和细化初始阶段是迈向细化阶段的一小步。在该阶段决定基本的可行性、风险和范围,对项目是否值得深入调查进行决策。初始阶段可能的活动和制品包括:(1)简短的需求讨论会。(2)大多数参与者、目标和用例名称。(3)大多数以摘要形式编写的用例。以详述形式编写10%~20%的用例,以加深对范围和复杂性的理解。(4)确定大多数具有影响和风险的质量需求。(5)编写设想和补充性规格说明的第一个版本。(6)风险列表。(7)技术上的概念验证原型和其他调查,用以揭示特殊需求的技术可行性。(8)面向用户界面的原型,用于确定对功能需求的设想。(9)对购买/构建/复用构件的建议,在细化阶段进行精化。(10)对候选的高层架构和构件给出建议。(11)第一次迭代的计划。(12)候选的工具列表。细化:构建核心架构,解决高风险元素,定义大部分需求,预计总体进度和资源。在细化阶段可能出现的一些关键思想和最佳实践包括:(1)实行短时间定量、风险驱动的迭代。(2)及早开始编程。(3)对架构的核心和风险部分进行适应性的设计、实现和测试。(4)尽早、频繁、实际地测试。(5)基于来自测试、用户、开发者的反馈进行调整。(6)通过一系列讨论会,详细编写大部分用例和其他需求,每个细化迭代举行一次。面向对象分析和设计的实质是一种系统建模的技术,它不是从功能或算法上考虑整个系统,而是从系统的组成上进行分解,利用类及对象作为软件的基本构造单元,以更接近人类思维的方式建立模型,从而使设计出的系统尽可能直接的描述现实世界,构造出模块化、可重用、易维护的软件。动态模型:有助于设计逻辑、代码行为或方法体。例如UML交互图。动态模型倾向于创建更为有益、困难和重要的图形。静态模型:有助于设计包、类名、属性和方法特征标记(但不是方法体)的定义,例如UML类图。敏捷建模采取了并行创建这两种模型的方式。二、对象模型领域模型是概念类或者感兴趣领域的现实对象的可视化表示。UML表示法中,用一组不定义操作的一组类图来说明。领域模型是现实世界概念类的一种表示,不是软件组件的一种表示。它不是描述软件类的图集,也不是有着职责的软件对象。2.1创建领域模型的步骤:用概念类分类列表和名词短语识别的方法找出当前需求中的候选概念类。在领域模型中描述这些概念类。在概念类之间添加必要的关联来记录那些需要保存记忆的关系。添加用来实现需求的必要属性。注意:概念类和属性命名时使用问题域中的词汇。一个领域模型可以将那些与当前需求无关的概念类排除在问题域之外。领域模型应当排除不包含在当前考虑下的问题域中的事物。2.2识别类及其属性对象是对问题域中有意义的事物的抽象,它们既可能是物理实体,也可能是抽象概念。具体地说,大多数客观事物可分为下述5类:(1)可感知的物理实体,例如,飞机、汽车、书、房屋等等。(2)人或组织的角色,例如,医生、教师、雇主、雇员、计算机系、财务处等等。(3)应该记忆的事件,例如,飞行、演出、访问、交通事故等等。(4)两个或多个对象的相互作用,通常具有交易或接触的性质,例如,购买、纳税、结婚等等。(5)需要说明的概念,例如,政策、保险政策、版权法等等。在分析所面临的问题时,可以参照上列5类常见事物,找出在当前问题域中的候选类与对象。另一种更简单的分析方法,是所谓的非正式分析。这种分析方法以用自然语言书写的需求陈述为依据,把陈述中的名词作为类与对象的候选者,用形容词作为确定属性的线索,把动词作为服务(操作)的候选者。当然,用这种简单方法确定的候选者是非常不准确的,其中往往包含大量不正确的或不必要的事物,还必须经过更进一步的严格筛选。通常,非正式分析是更详细、更精确的正式的面向对象分析的一个很好的开端。2.3审查类(1)冗余相同的类使用多于一个的名字。注意:近似的对象不一定完全相同,应该确定是否值得建立不同的类。(2)系统边界之外现实世界中存在许多对象,不能把它们都纳入到系统中去,仅需要把与本问题密切相关的类与对象放进目标系统中。有些类在其他问题中可能很重要,但与当前要解决的问题无关,同样也应该把它们删掉。(3)操作指被系统或者在系统内部完成的事件的名词。应该慎重考虑它们在本问题中的含义,以便正确地决定把它们作为类还是作为类中定义的操作。通过判断一个事件或者操作的实例是否包含状态、行为或者特征,如果没有,则不应该是类。(4)属性一个名词明显表示一些不具有感兴趣行为的简单事情,它是另一个类的属性。当然,如果某个性质具有很强的独立性,则应把它作为类而不是作为属性。判断是概念类或属性的原则:如果我们不将概念类X看成是现实世界中的数字或者文本,X就可能是概念类而非属性。(5)实现在分析阶段不应该过早地考虑怎样实现目标系统。因此,应该去掉仅和实现有关的候选的类与对象。在设计和实现阶段,这些类与对象可能是重要的,但在分析阶段过早地考虑它们反而会分散我们的注意力。(6)描述概念类在下列情况下,添加概念类的规格说明或描述:当需要商品或者服务的信息描述,独立于那些商品或者服务当前已存在的任何示例。由于与被删除的事物之间存在不正确的关联信息,删除它们所描述的事物实例会导致仍需维护信息的丢失。能够减少冗余或者重复的信息。2.4属性审查属性对问题域的基本结构影响很小。随着时间的推移,问题域中的类始终保持稳定,属性却可能改变了,相应地,类中方法的复杂程度也将改变。(1)是否在系统责任之内属性不是越详细越好,关键看是否是当前系统感兴趣的属性。(2)属性是否描述类对象的特征(3)属性是否存在冗余常见冗余如:出生年月--年龄(4)是否有1对多的复杂属性1:1--可以在原类内展开1:N--独立出去形成关联如果一个会员只有一个联系地址,可以在原类内展开,如果包含多个联系地址,则将联系地址独立出去形成关联。(5)属性是否对类的所有对象都有意义类图(修订1)2.5识别类之间的泛化泛化:子类通过继承拥有超类的特征关联:对象通过组装拥有其他对象的特征类A具有类B的全部属性和操作,而且具有自己特有的某些属性和操作。A称为B的子类,B称为A的超类。泛化举例:两种方式建立泛化关系:自底向上:抽象出现有类的共同性质泛化出父类,这个过程实质上模拟了人类归纳思维过程。自顶向下:把现有类细化成更具体的子类,这模拟了人类的演绎思维过程。2.6审查泛化关系(1)问题域是否需要这样的分类?(例:书——善本书)(2)系统责任是否需要这样的分类?(例:职员——本市职员)(3)是否符合分类学的常识?(用“isa”去套)(4)是否构成了继承关系?(确实继承了一些属性或服务,如航标船与一般的船)2.7识别类之间的关联类A与类B关联,如果类A在物理上或逻辑上是B的一部分;类A的对象向类B的对象发送一个消息;类A的对象建立类B的对象;类A的对象包含一个属性,属性的取值是类B的对象或者类B的对象集合;对象之间的静态联系是指,最终可通过对象属性来表示的一个对象对另一个对象的依赖关系。对象之间的动态联系是指,对象之间在行为(服务)上的依赖关系。在一个领域模型中需要考虑下面的关联:(1)那些需要将概念之间的关系信息保持一段时间的关联(“需要知道”型关联)。(2)从通用关联列表中派生出的关联。通用关联列表A在物理上是B的一部分A在逻辑上是B的一部分A在物理上包含在B中/依赖于BA在逻辑上包含在B中A是对B的描述A是交易或报表B中的一项A为B所知/为B所记录/录入B中/为B所捕获A是B的一个组织子单元A使用或管理BA与B通信A与一个交易B有关A是一个与另一个交易B有关的事务A与B相邻A为B所拥有A是一个与B有关的事件关联的指导原则:(1)将注意力集中在那些需要将概念之间的关系信息保持一段时间的关联。(2)识别概念类比识别关联更重要(3)太多的关联不仅不能有效地表示领域模型,反而会使领域模型变得混乱。有时,(4)发现某些关联很费时,但带来的好处并不大。(5)避免显示冗余或导出的关联。聚合vs.组合识别聚合(组合)结构的意义:在动态建模时帮助进行职责分配。举例:发给订单的修改订单项消息,在内部是通过调用订单项的修改消息完成的。比较:关联的几种表现形式代码:聚合+单向连接(1:1)代码:聚合+单向连接(1:n)代码:组合(1:1)代码:组合(1:n)2.8识别聚合(组合)思路(1)物理上的整体事物和它的组成部分(2)组织机构和它的下级组织(3)团队(组织)和成员(4)空间上的包容(5)抽象事物的整体和部分2.9识别连接(1)将注意力集中在那些需要将概念之间的关系信息保持一段时间的关联。(2)识别实体类比识别关联更重要。(3)太多的关联不仅不能有效地表示对象模型,反而会使对象模型变得混乱。(4)避免显示冗余或导出的关联。类图(修订2)课堂作业:请大家动手做根据前面的类图,识别类之间的关联(聚合、组合、连接),要说明多重性,如果关联的形式是“连接”,还要注明关联名。三、动态模型几乎解决任何一个问题,都需要从客观世界实体间的相互关系中抽象出有价值的对象模型;当问题涉及交互作用和时序(如用户界面或过程控制等),动态模型是必不可少的。3.1顺序图的作用表示用例的行为顺序,描述对象之间以及对象与Actor之间的消息发送关系;发现类并依据其职责构建类的属性和方法。SSD应为用例的主要成功场景以及频繁或复杂的替代场景而设计。3.2三种版型的类边界类:用来控制与外界交互的类。控制类(可选):控制事件流,负责为实体类分配责任实体类:为持续存在的对象建模,系统也需要保存关于这些对象的长期信息。举例:SelectCourse(选课用例)事件流:为了使问题更简单一些,不考虑学生的登陆。假设学生已经成功登陆系统,选课的事件流如下: (1)学生进入选课主界面。 (2)学生选择选课。 (3)系统显示所有课程信息。 (4)学生选择课程。 (5)系统验证课程是否可选。5a:课程不可选 (6)系统提示课程选择成功,提示学生交费。 (7)用例结束。 5a:课程不可选 (1)系统提示课程不可选及原因。 (2)学生重新选课。 (3)重新验证直至成功。 (4)转选课事件流第6步。分析对象、角色之间交互的消息。本用例主要有以下交互: (1)学生向界面对象发送选课命令。 (2)界面向控制对象请求课程信息。 (3)控制对象向课程对象发送查询课程消息。 (4)界面对象从控制对象中取得所有的课程信息。 (5)在界面上显示所有的课程信息。 (6)学生选择课程。 (7)界面对象向控制对象发送消息,查询该生是否可以选择选定的课程。 (8)控制对象从学生选课信息对象中查询关联信息。 (9)控制对象判断是否可以选课。 (10)如果可以选课,则向选课对象中添加关联信息。 (11)向界面对象返回选课成功信息。注意:为了支持有条件和循环的构造,UML使用了图框(Frame)。图框是图的区域或片段,在图框中具有操作符或标签和保护信息(条件子句)。常见的图框操作符有:Alt:选择性的片段,用于表示保护信息所表达的互斥条件逻辑。Loop:用于表示保护信息为真的循环片段。Opt:当保护信息为真时执行的可选片段。Par:并行执行的并行片段。Region:只能执行一个线程的临界片段。3.3顺序图和类图的映射消息的传入:类对象所具有的操作--责任消息的传出:类对象完成操作所需合作--协作练习1、Course类有几个消息2、ControlObject对象的QueryAssociation(int,int)操作内部的代码。结账UC.检查(){ 会员.检查账户状态(); 库存.检查库存();}补充:用操作契约增加细节契约是为系统操作而定义的——这种操作是作为黑箱的系统在其公共接口中提供的,用于处理输入系统事件。系统操作可以通过发现这些系统事件来识别。契约中的条目:操作(例如enterItem(itemID:itemID,quantity:integer))交叉引用:(可选择)可能发生此操作的用例。前置条件:后置条件:描述领域模型中对象状态的变化。包括三类:实例的创建和删除。属性的修改。关联的形成和断开。书写契约将导致领域模型的更新。要创建契约时,应用下面的建议:(1)从SSD识别系统操作。(2)对于那些复杂的、结果微妙的以及在用例中不清晰的系统操作,构造一个契约。(3)要描述后置条件,使用下面的分类:实例的创建和删除。属性的修改。关联的形成和断开。3.4状态图对于一个给定的类,可以把事件、状态和状态转移的方式进行抽象,并用一个状态图表示。状态图(StatechartDiagram)主要用于描述一个对象在其生存期间的动态行为,表现一个对象所经历的状态序列、引起状态转移的事件(event)以及因状态转移而伴随的动作(action)。在状态图中,状态是对某一时刻中属性特征的概括。支票(对象)已付(状态)汽车(对象)停在那儿(状态)发动机(对象)正在运行(状态)吉姆(对象)正在卖货(状态)小王(对象)已婚(状态)每个状态框中有两格:上格放置状态名称,下格说明处于该状态时,系统或对象要进行的活动。动作(action)与活动(activity)区别:activity与一个状态关联,当一个状态进入时开始,需要一段时间执行,可以被中断。Action与一个转移相关联,在较少的时间内完成,其操作具有原子性,通常发生于状态的初始化、进入和退出时。教学后记**“教学后记”是授课完毕之后,教师对授课准备情况、授课过程及授课效果的回顾与总结,因此,教师应及时手写补充完整本部分内容。时间安排4次课章节名称面向对象设计教学目的掌握各种设计模式的运用教学重点与难点GRASP设计模式的运用。GOF设计模式的了解。教学内容与过程设计教学内容与过程设计分析和设计分析强调的是对问题和需求的调查研究,而不是解决方案。例如,如果需要一个新的计算机化的图书馆信息系统,那么应该如何使用这一系统?设计是软件生命周期中最需要智力、最有创造性的部分,这部分工作体现了软件开发过程真正的复杂性。设计强调的是满足需求的概念上的解决方案,而不是其实现。例如,对数据库方案和软件对象的描述。最终,设计可以被实现。设计模式简介复用:复用的概念与软件行业一样悠久。20世纪50年代中期,成立了一个有关IBM大型机在科学应用方面的用户组织,该组织最重要的功能之一是作为交换软件子程序的场所。这个组织叫做share,会员所捐献的子程序可能就是世界上第一个可复用的软件库。然而,构建小规模的可复用组件是一回事,构建大规模的可复用组件是完全不同的另一回事,但是大规模复用的问题至今还没有基本解决。因为有关大规模复用的问题有很多的争议。首先,有人提倡大规模复用是软件的发展方向,将来的软件就是对已有组件的组合(称之为基于组件的软件工程)。而其他人,特别是更好理解软件业的人,却认为几乎不可能抽象出足够的功能,并在此基础上开发专用的、适合当前问题的组件。上述复用通常指代码复用,而设计模式复用是另一个层次上的复用。通常,设计模式指的是一种多次出现的设计结构或解决方案。如果对他们进行系统的归类,即可被重用,可以构成不同设计之间通信的基础。设计模式源于实践,而不是源于理论。模式就是已命名的问题-解决方案公式,是经过系统整理的经典设计原则。责任分配vs.功能分解系统设计中的关键问题包括:(1)应该如何为对象类分配职责?分配职责是必须要执行的一项活动(无论是在画UML图时还是在编程时,都是如此),并且它对软件组件的健壮性、可维护性和可重用性具有重要影响。(2)对象应该如何交互?(3)什么样的类应该做什么样的事情?其实就是模式的概念。思考软件对象设计以及大型构件的流行方式是,考虑其职责、角色和协作。这是被称为职责驱动设计的大型方法的一部分。在RDD中,我们认为软件对象具有职责,即对其所作所为的抽象。UML把职责定义为“类元的契约或义务”。就对象的角色而言,职责与对象的义务和行为相关。职责分为以下两种类型:行为和认知。对象的行为职责包括:1、自身执行一些行为,如创建对象或计算。2、初始化其他对象中的动作。3、控制和协调其他对象中的活动。对象的认知职责包括:1、对私有封装数据的认知。2、对相关对象的认知。3、对其能够导出或计算的事物的认知。准则:领域模型展示了对象的属性和相互关联,因此可以从领域模型中推理出与认知型相关的职责。职责的粒度会影响职责到类和方法的转换。大粒度职责具有数百个类和方法。小粒度职责可能只有一个方法。RDD也包括了协作的思想。职责借助于方法来实现,该方法既可以单独动作,也可以与其他方法和对象协作。(一)低耦合问题:怎样降低依赖性,减少变化带来的影响,提高重用性?解决方案:分配职责以使(不必要的)耦合保持在较低的水平。用该原则对可选方案进行评估。在实际工作中,不能将耦合的级别与其他诸如专家模式和高内聚模式这样的原则孤立考虑。然而,耦合是提高设计质量必须考虑的一个因素。耦合(coupling):测量一个元素连接、了解或者依赖其他元素强弱的尺度。具有弱耦合的元素不过多地依赖其他元素。元素包括类、子系统、系统等。解耦合的典型案例:有轨列车,最初的列车只有一节车厢,即蒸气机与车厢一体的结构,随着火车的发展逐渐走向成熟,工程师们发现这样的结构扩充起来相当困难,无限制增加车厢的长度显然不切实际,不但工艺上要求更高,成本因此大幅增加,而超长的车身对于弯度较大的轨道而言也难以适应。于是人们开始将车厢与机车分离开来单独制造,运行时相互挂接,这样一来降低了成本,二来避免了轨道弯度的问题,三来也大大增强了列车配置的灵活性,既可随时根据需求灵活调整列车的组成,也可以在当某节车厢发生机械故障时快速更换。松散耦合举例:模块之间的好的耦合关系会松散到恰好能使一个模块能够很容易地被其他模块使用。火车模型之间通过环钩彼此相连,把两辆列车连起来非常容易——只用把它们钩起来就可以了。设想如果你必须用螺钉拧在一起,或者要连很多线缆,或者只能连某些特定种类的车辆,那么连接工作会有多么复杂。常见的耦合形式:在面向对象语言(C++、java、C#)中,从X到Y的耦合的常见形式包括:(1)X具有引用Y实例或者Y本身的属性(数据成员或者实例变量)。(2)X调用Y对象中的服务。(3)X具有引用Y实例或者Y本身的方法。这种情况表现为方法具有Y类型的参数或者Y类型的局部变量,或者从消息返回的对象是Y的实例。(4)X是Y的直接或者间接的子类。(5)Y是一个接口,X实现了这个接口。低耦合模式鼓励职责分配时不增加耦合性,从而避免了高耦合可能产生的不良后果。一般来说,那些本质上很一般化的类,它们具有很大的重用可能性和低耦合性。本质上,高耦合不是问题,问题是在某种尺度上与不稳定的元素高耦合,例如不稳定元素的接口、实现或者不稳定元素的纯粹存在。优点:(1)不受其他组件改变的影响。(2)便于单独理解(3)重用方便。高耦合的问题:(1)具有高耦合性的类过多地依赖其他类。(2)相关类的变化强制局部变化。(3)当元素分离出来时很难理解。(4)因为使用高耦合类时需要它所依赖的类,所以很难重用。设计良好的类接口的一些建议:1、尽可能地限制类和成员的可访问性。2、避免友元类,因为他们之间是紧密耦合的。3、在基类中把数据声明为private而不是protected,以降低派生类和基类之间耦合的程度。4、要对从语义上破坏封装性保持警惕。什么是语义上的耦合?一个模块不仅使用了另一个模块的语法元素,而且还使用了有关那个模块内部工作细节的语义知识。例如:1、Module1向Module2传递了一个控制标志,用它告诉Module2该做什么。这种方法要求Module1对Module2的内部工作细节有所了解,也就是说需要了解Module2对控制标志的使用。2、Module2在Module1修改了某个全局数据之后使用该全局数据。这种方式就要求Module2假设Module1对该数据的修改符合Module2的需要,并且Module1已经在恰当的时间被调用过。3、Module1把Object传给Module2。由于Module1知道Module2只用了Object的7个方法中的3个,因此它只部分地初始化Object——只包含那3个方法所需要的数据。4、Module1把BaseObject传给Module2。由于Module2知道Module1实际上传给它的是DerivedObject,所以它把BaseObject转换成DerivedObject,并且调用了DerivedObject特有的方法。语义耦合非常危险,因为更改被调用的模块中的代码可能会破坏调用它的模块,破坏方式是编译器完全无法检查的。(二)高内聚从对象设计的角度看,内聚是一个元素的职责被关联和关注的强弱尺度。如果一个元素具有很多紧密相关的职责,而且只完成有限的功能,则这个元素就具有高内聚性。低内聚的问题具有低内聚的类会执行许多互不相关的事物,或者完成太多的功能。这样的类是不可取的,它们会导致如下一些问题:难于理解;难于重用;难于维护;系统脆弱,常常受到变化带来的影响。低内聚类常常代表抽象化的“大粒度对象”,或者承担着应该委托给其他对象的职责。实际工作中,考虑内聚程度时不能与其他职责和其他原则相分离。根据经验,一个具有高内聚的类具有数目相对较少的方法和紧密相关的功能,但是它并不完成太多的工作。当需要实现的任务过大时,它可与其他对象协作来分担过大的工作量。一个类具有高内聚性是非常有利的,因为它的理解、维护和重用都相对容易。高度相关的功能,与少量操作绑定在一起,还可以简化维护和扩展。具有高度相关功能的细粒度也增加了重用的潜力。例子:高内聚模式也是现实世界的类推。显而易见,如果一个人完成太多的本应委托给别人完成的毫不相关的职责,这个人就不会有高效率。例如一些还没学会怎样委托任务的经理,经常受着低内聚带来的种种困难;他们应该准备好将职责“拆分”到更多的人身上。高内聚的优点(1)设计的清晰性和易于理解性得到提高。(2)维护和扩展得到简化。(3)常常支持低耦合。(4)强相关的功能所组成的细粒度组件增加了重用性,因为一个内聚度高的类能够针对一个非常明确的目的进行重用。限制:在少数情况下接受低内聚是合理的。其中一种情况是:具有低内聚的组件是分布式的服务器对象。为了使远程通信所带来的通信开支降低,有时只创建很少的具有低内聚的大型服务器对象来为许多操作提供接口是可取的。在这种情况下,远程操作的粒度更粗,以便在远程操作调用中,可以完成或请求更多的工作,这样能够减轻网络的远程调用对于性能的不良影响。(三)创建者模式问题:谁应该负责创建某类的新实例?解决方案:如果符合下面的一个或者多个条件,则可将创建类A实例的职责分配给类B。类B包含或组成聚合类A的对象。类B记录类A对象的实例。类B直接使用类A的对象。类B初始化数据并在创建类A的实例时传递给类A(因此,类B是创建类A实例的一个专家)这时可以说,类B是类A对象的创建者。创建者模式指导我们分配那些与创建对象有关的职责。创建者模式的基本意图是寻找在任何情况下都与被创建对象具有连接的创建者。如此选择是为了保持低耦合。创建者模式建议:封装的容器或者记录器类是创建自己包含或者记录的元素的很好候选者。举例:谁应该负责创建SalesLineItem实例?按照创建者模式,我们应当找聚合、包含SalesLineItem实例的类。即Sale。限制:创建过程经常非常复杂,比如因为性能原因需要重复使用实例,或者需要根据一个外部属性值从一族相似类中创建一个类的实例,等等。在这些情况下,最好的方法是将创建委托给一个称为工厂的辅助类,而不是使用创建者模式所建议的类。优点:由于被创建类对于创建类已经可见了,因此是低耦合的。(四)信息专家模式问题:给对象分配职责的基本原则是什么?解决方案:把责任分配给信息专家,它具有实现这个职责所必需的信息。当信息分布在不同对象中时,各个对象需要通过消息来进行交互以共享相关工作。信息专家模式——同对象技术中的许多其他事物一样——与现实世界具有相似性。我们通常把职责分配给具有完成某项职责所需信息的个体。例如,在一个企业中,谁应该负责做出盈利或者亏损的结论?当然是那些能够得到全部财务信息的人才能做出这种结论。可能这个人就是首席财务官。就像软件类之间的协作一样,财务官所需要的信息可能很分散,因此他就需要别人的协作。公司的首席财务官可能会要求会计师生成有关贷款或者债务的报告。限制:在某些情况下,专家模式所表述的解决方案并不合适,通常这是因为耦合和内聚中的问题。例如,谁应该负责把一个sale类信息存入数据库中?显然,许多需要存储的信息都位于Sale对象中,根据专家模式,认为应将这个职责分配给Sale类。一旦这样决定,以此类推,每个类都具有存储自身信息到数据库的服务。但这将导致内聚、耦合以及重复的问题。例如,Sale类必须包括有关数据库的逻辑处理,这样Sale就不仅仅关注“作为销售”的纯粹应用逻辑,它还必须具有其他种类的职责,这些其他职责降低了它的内聚性。同时,Sale类必定会与其他子系统的数据库服务耦合,而不是耦合到软件对象领域层中的其他对象,这导致耦合度上升。而且,这也将导致相似的数据库逻辑在每个持久类中重复出现。上述问题违背了基本的架构原则:即设计是为了将主系统不同的逻辑方面进行隔离。应将应用逻辑置于一个地方(如领域软件对象),数据库逻辑置于另一个地方(如一个独立的持久服务层),等等,而不应在同一个组件中混合系统的不同方面。优点:因为对象使用自己的信息来实现任务,所以信息的封装性得以维持。这就支持了低耦合,提高了系统的健壮性和可维护性。行为分散在不同的类中,这些类各自具有完成行为所需要的信息。这鼓励我们定义了更多具有强内聚性的“轻量级”类,这些类更易于理解和维护。(五)老板原则当出现以下情况时,发给A的消息先通过B处理和中转。B聚合A(Aggregation)B组合A(Composition)优点:支持低耦合,这种设计意味着具有更低的维护依赖性和更高的重用机会。之所以可能不增加耦合性,是因为A对于B已经可见了。(六)可视原则如果某个对象要发送消息到另一个对象时,它必须拥有对接收消息对象的可见性。(七)控制器模式问题:怎样将UI层连接到应用逻辑层?解决方案:把接收和处理系统事件消息的职责分配给一个类,这个类表示以下一项内容:(1)表示整个系统、设备或者子系统(外观控制器)。(2)表示一个发生系统事件的用例场景,这个类通常被命名为“<用例名>处理器”、“<用例名>协调器”或者“<用例名>会话”(用例或会话控制器)。一个控制器就是负责接收或者处理系统事件的非用户接口对象。一个控制器定义系统操作的方法。通常一个控制器应当把要完成的功能委托给其他对象,它只是进行协调和控制,本身不完成太多的功能。在设计控制器时,一个常犯的错误是赋予它们过多的职责。当系统不具有“太多”的系统事件,或者用户接口不可能将事件消息重定向到交互的控制器(比如在消息处理系统中)时,选择外观控制器是合适的。当分配职责到一个外观控制器中时会导致设计的低内聚和高耦合,即外观控制器由于过多的职责而变得“臃肿”的时候,可以选择为每个用例构造一个用例控制器。反复强调:控制器模式的一个重要的必然结果是接口对象和接口层不应该有处理系统事件的职责。即系统操作应该在对象的应用逻辑或者领域层中得到处理,而不应该在系统的接口层得到处理。控制器是从接入层进入领域层的一种外观.在UP和Jacobson的旧式对象方法中,具有边界类、控制类和实体类的可选概念。边界对象是接口的抽象,实体对象是独立于应用程序的领域对象,控制对象是控制器模式中描述的用例处理器。重用的潜力增强,可提供插件式界面。案例——零件销售系统(设计)举例——结帐用例的基本路径1.会员请求结账2.系统检查账户是否处于打开状态3.系统检查库存是否满足4.系统检查会员提交的信息是否充分5.系统合计订单总价(订单总价=所有订单项价钱合计+税金+运费)6.系统显示收费明细7.会员确认8.系统通知供应商发货,减少相应库存数量责任分配给谁?应用:专家+老板原则专家原则:谁知道“帐户状态”?只有某个会员的“帐户”对象知道帐户状态,因此将责任分配给“帐户”对象。老板原则:“会员”对象与“帐户”对象之间存在聚合的关系,因此责任先分配给“会员”对象,然后再由“会员”对象分配给“帐户”对象。类图和代码变化会员.检查账户状态(){ … 账户.检查状态() …}责任分配给谁?分析过程:目前没有一个设计类知道销售总额,所以我们要设计对象的交互来满足此需求。1)陈述职责:谁应该负责了解销售总额?2)概括所需信息:销售总额是所有销售条目的小计之和。销售条目小计=销售条目数量×产品描述单价3)列出实现此职责所需的信息和了解这些信息的类。ProductDescription.priceProductDescriptionSalesLineItem.quantitySalesLineItem所有当前Sale中的SalesLineItemsSale下面我们对此推理过程进行更详细的分析:1、谁应该负责计算Sale的总额呢?根据信息专家模式,应该是Sale本身,因为它知道计算销售总额所必需的所有SalesLineItem实例。所以,Sale将承担获知总额的职责,用getTotal方法实现。2、Sale计算销售总额时,需要每一个SalesLineItem的销售小计。谁应该负责计算SalesLineItem的销售小计呢?根据信息专家模式,应该是SalesLineItem本身,因为它知道其数量和与之关联的ProductDescription。因此,SalesLineItem将承担获知总计的职责,用getSubtotal方法实现。3、SalesLineItem计算其销售小计时需要知道ProductDescription的价格。谁应该负责提供ProductDescription的价格呢?根据信息专家模式,应该是ProductDescription本身,因为它将价格封装为它的一个属性。因此,ProductDescription将承担获知价格的职责,用getPrice()方法实现。同样符合可视原则谁来计算税金?应用专家原则,计算税金需要用到的信息:税金=价钱×相应税率考虑:订单知道所有这些吗?解决方法:添加一个“计费”类,负责计算各种附加费用。计算运费也是如此。准则:1、当存在多个可选设计时,应更深入地观察可选设计所存在的内聚和耦合,以及未来可能存在的进化压力。选择具有良好内聚、耦合和在未来出现变化时能保持稳定的设计。2、当有多个局部信息专家有待选择时,将职责赋予具有支配作用的信息专家,即持有主要信息的对象。这样有助于支持低耦合。3、当存在多个设计选择时,考虑每个选择对耦合和内聚的影响,由此选择最佳的方案。4、当基于其他准则还是无法明确地选择出适当的方案时,则要考虑这些软件对象在未来可能的演化以及信息专家、内聚和耦合等方面的影响。补充:关于初始和“启动”用例的说明。在编码时,至少首先要编写启动初始化的程序。但是在OO设计建模的过程中,要最后考虑启动初始化,知道发现哪些是真正需要被创建的和初始化的。然后,再对初始化进行设计以支持其他用例实现的需要。对于所有的情形,常见的设计约定是创建一个初始领域对象或一组对等的初始领域对象,这些对象是首先要创建的软件“领域”对象。这些创建活动可以显式地在最初的main方法中完成,也可以从main方法调用Factory对象来完成。通常,一旦创建了初始领域对象,该对象将负责创建其直接的子领域对象。那么如何选择初始领域对象呢?选择位于或接近领域对象包含或聚合层次中的根类作为初始领域对象。该类可能是外观控制器,也可能是容纳所有或大部分其他对象的某些对象。对高内聚和低耦合的考虑将影响对这些候选者的选择。补充:命令-查询分离原则(Command-QuerySeparationPrinciple)任何方法都可能是如下情况之一:1、执行动作(更新、调整等)的命令方法,这种方法通常具有改变对象状态等副作用,并且是void的(没有返回值)。2、向调用者返回数据的查询,这种方法没有副作用,不会永久性地改变任何对象的状态。关键是,一个方法不应该同时属于以上两种类型。CQS被公认为是计算机科学理论中具有价值的原则,因为遵循该原则,你能够更容易地推测出程序的状态,在查询状态时不会同时发生变更。如果应用一直遵循CQS,那么你会知道查询或getter方法不会作出任何修改,而命令也不会有任何返回。这是个简单的模式。细化迭代2——更多模式(一)多态(Polymorphism)问题:如何处理基于类型的选择?如何创建可插拔的软件构件?基于类型的选择——条件变化是程序的一个基本主题。如果使用if-then-else或case语句的条件逻辑来设计程序,那么当出现新的变化时,则需要修改这些case逻辑——通常遍布各处。这种方法很难方便地扩展有新变化的程序,因为可能需要修改程序的多个地方——任何存在条件逻辑的地方。可插拔软件构件——客户-服务器关系中的可视化构件,如何才能够替换服务器构件,而不对客户端产生影响呢?解决方案:当相关选择或行为随类型(类)变化而变化时,用多态操作为变化的行为类型分配职责。推论:不要测试对象的类型,也不要用条件逻辑来执行基于类型的不同选择。例如:第三方税费计算器,接口不同,一个可能支持TCPsocket协议,一个提供SOAP接口,第三个提供JavaRMI接口。由于税费计算器适配的行为随计算器的类型会不同,因此根据多态模式,应该将适配的职责分配给不同的税费计算器适配器对象自身,用多态操作getTaxes来实现。每个税金计算器具有不同的接口,因此需要有类似但不同的行为以适配每种外部的固定接口或API。这些计算器适配器对象并非是外部的计算器,而是表示外部计算器或计算器适配器的本地软件对象。通过向该本地对象发送消息,最终将会产生对外部计数器本地API的调用。每个getTaxes方法都以Sale对象作为参数,这样才能够使计算器分析销售。多态的含义:当对象的服务相似或相关时“为不同对象的服务提供一个相同的名称”。通常,不同的对象类型通过实现同一接口或继承同一个超类来实现多态。典型案例两种不同的适配器接口(介绍一下Java的容器类库的设计思想,接口,抽象类)(1)转换接口是为了克服与表示方法、数据结构或硬件特点相关的操作给重用带来的困难而设计的,这类接口是每个类构件在重用时都必须重新定义的服务的集合。当使用C++语言编程时,应该在根类中,把属于转换接口的服务定义为纯虚函数。(2)扩充接口扩充接口与转换接口不同,并不需要强迫用户在派生类中重新定义它们,相反,如果在派生类中没有给出扩充接口的新算法,则将继承父类中的算法。当用C++语言实现时,在基类中把这类服务定义为普通的虚函数。讨论:多态是一个基本的设计原则,用于设计系统如何组织以处理类似的变化。基于多态分配职责的设计能够被简单地扩展以处理新的变化。准则:何时使用接口进行设计多态意味着在大部分OO语言中要使用抽象超类或接口。何时应该考虑使用接口呢?普遍的答案是,当你想要支持多态但是又不想约束于特定的类层次结构时,可以使用接口。优点:(1)扩展性要求能方便地增加新变化。(2)引入新实现不影响客户端程序。(3)选定消息时无需询问消息是“何种类型”。(二)纯虚构(PureFabrication)问题:当你并不想违背高内聚和低耦合或其他目标,但是基于专家模式所提供的方案又不合适时,哪些对象应该承担这一职责?面向对象设计有时会被描述为:实现软件类,使其表示真实世界问题领域的概念,以降低表示差异。然而,在很多情况下,只对领域层对象分配职责会导致不良内聚或耦合,或者会降低复用潜力。解决方案:对人为制造的类分配一组高内聚的职责,该类并不代表问题领域的概念——虚构的事物,用以支持高内聚、低耦合和重用。通常虚构类的设计非常简洁或纯粹——因为它是一个纯虚构的设计元素。即,一个纯虚构意味着面临设计困难时我们可以虚构出设计元素。例如:假设需要在关系数据库中保存Sale的实例。根据信息专家模式,Sale类要求大量的支持面向数据库的操作,这将导致Sale类不是内聚的,且耦合度上升(Sale类不得不与关系数据库的接口耦合)。同时对于其他许多类而言,对象存储到关系数据库是一个非常通用的功能,在Sale类中实现此职责表明其他类很难重用它或在其他类中重复实现此职责。一种合理的方法:创建一个只负责在某种存储介质中保存对象的新类。这个类是一个纯虚构。例如:PersistentStorage纯虚构能解决如下设计问题:(1)Sale类可以继续保持高内聚、低耦合的良好设计。(2)PersistentStorage对象本身相对内聚,它的唯一功能是在持久存储介质中存储或插入对象。(3)PersistentStorage是个非常一般和可重用的对象。纯虚构通常是基于相关的功能性进行划分,是一种以功能为中心的对象或行为对象。(行为分解而非表示分离而得到的对象)大量现有的面向对象设计模式都是纯虚构的例子:适配器(Adapter)、策略(strategy)、命令(Command)等。优点:因为职责被分解成为只关注一组非常具体的相关任务的细粒度类,所以设计支持高内聚。由于细粒度的纯虚构类的职责可以应用在其他应用程序中,因而重用的可能性也可能增加。(三)中介(Indirection)问题:为了避免两个或多个事物之间直接耦合,应该如何分配职责?如何使对象解耦合,以支持低耦合并提高复用性潜力?解决方案:将职责分配给中介对象,使其作为其他构件或服务之间的媒介,以避免它们之间的直接耦合。中介实现了其他构件之间的间接性。例如:税费计算器适配器协调系统与外部税费计算器的工作。通过在系统的边界上增加一个中介层和运用多态设计技术,适配器类保证了系统内部的设计不会随着外部系统接口的变化而变化。例如:引入PersistentStorage类来解除Sale类与关系数据库服务之间的耦合。PersistentStorage是Sale类和数据库之间的中介对象。讨论:计算机科学中的大多数问题都可以通过增加一层间接性来解决。许多设计模式也都是间接性的特例。例如适配器、外观(Facade)和观察者等。此外,许多纯虚构是因为间接性而产生的。间接性的动机通常为了低耦合,即在其他构件或服务之间加入中介以进行解耦。优点:实现了构件之间的低耦合。(四)受保护变化(ProtectedVariations)问题:如何设计对象、子系统和系统,使其内部的变化或不稳定性不会对其他对象、子系统和系统产生不利影响?解决方案:识别可预知的变化或不稳定

温馨提示

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

评论

0/150

提交评论