软件工程导论
软件工程导论
还有5天就要考软件工程导论了!不得不吐槽一下这门课程有多么水,一个学期我就去上了两次课,偌大一个80几人的课堂最后被老师逼走得只剩下个位数去上课。唉,老师怡然自得在讲台上用小学生英语念PPT,不想上课了就安排同学们上机。大学里这种水水的老师真见得不少,但是真才实学的老师也有,值得我们尊敬和敬佩!!可惜和他们接触好少。我想以后如果读研在国内的话,没有碰见好导师简直浪费光阴了,对于我这种需要氛围来带动学习的人来说。昨天看见知乎上说国内互联网氛围最浓的大学是北邮,隔三差五各种技术大牛的讲座,同学们之间各种编程比赛和团队学习~当初为什么木有去北邮呢。。。。老哥建议我去华科的,结果想着大学好不容易解放了不想再去苦逼的理工科学校。结果,一失足千古恨。其实,奋斗的过程永远没有终点,无论你取得了多大的成功,只要你开始放纵自己了,你又会被打回原来一无是处的自己。每天好好调节学习和生活,不一定非得用自己的健康当实现梦想的牺牲品。年轻的时候多刻苦学学但不也不至于头悬梁锥刺股,年纪大的时候才能从容生活。
艰难的复习。。。。。课本是SSD9,但是先把中文的清华出版的软件工程导论看一遍吧~这书的名字和我们专业名字一样,其实应该是最精华的课程之一才对。
一、1.为什么要学习软件工程?
20世纪70年代,随着计算机的日益普及,人们对软件的需求急剧上升,从而对软件的开发和维护出现了前所未有的困难,直至现在也没有摆脱软件危机的困扰。1968年,计算机科学家在联邦德国召开会议讨论软件危机的问题。至此,“软件工程”这个名词诞生了!它是一个从管理和技术两方面来研究如何更好地开发和维护计算机软件的学科。
(软件是程序,数据和文档的完整集合。)
2.软件工程的基本原理:(没有相关经验,所以在学校里根本就学不到真正的软件工程的知识)
用分阶段的生命周期计划严格管理。
坚持进行阶段评审。 错误发现改正的越早,代价越小。
实行严格的产品控制 不能随意修改软件的基准配置(各个阶段产生的文档和代码)
采用现代程序设计艺术
结果应能清楚地审查
开发小组的人员应该少而精
承认不断改进软件工程实践的必要性 积极主动地采纳新的软件技术,注意不断总结经验
3.软件工程方法学
传统方法学(生命周期方法或结构化范型)
把软件生命周期的全过程依次划分为若干个阶段,然后顺序地完成每个阶段的任务。而且每个阶段结束之前从技术和管理的角度进行严格的审查(文档),通过之后才能进行下一阶段的工作。
面向对象方法学
(软件规模庞大,对软件的需求是模糊的或会随时间的变化而变化的时候,此方法更成功)
传统方法学的技术要么面向行为(对数据的操作),要么面向技术。而面向对象方法学将行为和数据紧密地结合起来了。
要点:
基本单位:对象
所有对象划分为类
继承性:类分为父类和子类的关系。子类自动拥有父类的数据和操作
封装性:对象彼此之间仅能通过发送消息互相通信。必须向对象发消息请求它执行它的某个操作来处理数据,而不能从外界直接对它的数据进行处理。
以上两个特性促进了软件重用性和各项开发活动之间的无缝过渡。
4.软件生命周期(也就是传统方法学的过程)
软件定义 —–问题定义、可行性研究和需求分析(规格说明书)
、软件开发 ——-总体设计(分模块和模块间的联系)、详细设计(设计模块)、编码和单元测试(写和测试模块)、综合测试(集成测试和验收测试(有用户参与))
、软件维护- ——-每一次维护活动上本质都是一次压缩和简化了的定义和开发过程。修改错误,适应新环境,改进软件满足新需求,为将来的维护活动做准备。
后面好几章都是分部分介绍软件生命周期的。
5.软件过程
瀑布模型(用得最广泛,传统软件工程方法学的描述)
指导思想:清楚地区分逻辑设计与物理设计,尽可能推迟程序的物理实现。
文档驱动,可能导致最终开发出来的产品不能真正满足用户需求。
快速原型模型
快速建立一个能反映用户需求的原型系统,让用户在计算机上试用它,通过实践来了解目标系统的原型。开发人员通过用户的意见快速修改模型,最后再写规格说明文档。能真正迎合用户需求。
增量模型
第一个增量构件实现软件基本需求,提供最核心的功能。每个构件由许多相互作用的模块构成。把新构件集成到现有软件中时,所形成的产品必须是可测试的。
优点:逐步增加产品功能,使用户有充足的时间学习和适应新产品
缺点:需要更精心的设计,使得每个新增量构件集成到原来产品中时,不破坏原来已经开发出来的产品。有无法将构件集成的风险。
螺旋模型
在每个阶段之前都增加了风险分析的快速原型模型
风险驱动
喷泉模型
面向对象方法学的过程模型(迭代和无缝的特性)
Rational统一过程(RUP) [完整而且完美】
敏捷开发与极限编程(XP)
对变化和不确定性更快速和更敏捷的反应特性,因此可以较好地适应商业竞争环境下对小型项目提出的有限资源和有限开发时间的约束,可以作为对RUP的补充和完善;但不如RUP全面和完善
微软过程
可以看做RUP的一个精简配置版本,包含若干个生命周期的持续递进循环,每个生命周期由5个阶段组成,每个阶段精简为一次迭代完成;另一方面,可以看做是敏捷过程的一个扩充版本,它扩充了每个生命周期内的各个阶段的具体工作流程。
以上的内容只考选择题。。。。。。。。orz
6.需求分析
用实体-联系图建立数据模型 用数据流图建立功能模型 用状态图建立行为模型
数据字典把三种分析模型粘合在一起,准确定义了出现在模型中的数据对象及控制信息的特性。
IPO图是描述算法的有效工具
7.总体设计
设计原理:
模块化:模块化使软件容易测试和调试,也有助于软件开发工程的组织和管理。但并不是越多模块越好,随着模块的中增加,设计模块间的接口所需要的工作量也增加,每个人程序都相应地有一个最适当的模块数目M,使得系统开发成本最小。
抽象:处理复杂系统的唯一方法是用层次的方法构造和分析它,所以先抽象出高级的概念构造和理解,再依次用相对低级概念去构造和理解。
逐步求精:
为了能集中精力解决主要问题而尽量推迟对问题细节的考虑。
Miller法则:一个人在任何时候都只能把注意力集中在(7+-2个知识块上) ——–安排要解决问题的优先集
抽象和求精是一对互补概念
信息隐藏和局部化
信息隐藏:应该这样设计和确定模块,使得一个模块内包含的信息(过程和数据)对于不需要这些信息的模块来说,是不能访问的。模块彼此间交换的应该是为了完成系统功能而必须交换的信息。减少错误的传播。
局部化:把一些关系密切的软件元素物理地放得彼此靠近。
模块独立
两个定性标准度量:
耦合:衡量不同模块彼此间互相依赖(连接)的紧密程度。软件设计应追求尽可能松散耦合的系统。交换的信息仅仅是数据,则是数据耦合(低耦合)。传递的是控制信息,则称控制耦合(中等耦合)。控制耦合增加了系统的复杂度,往往模块分解后能用数据耦合替代。当传递的数据大于模块所需的数据时,便是特征耦合,给网络犯罪提高了机会。
当两个或多个模块通过一个公共数据环境相互作用时,称为公共环境耦合。
内聚:一个模块内部各个元素彼此结合的紧密程度。设计时应力求做到高内聚。一个模块只完成一个单独的子功能。高内聚意味着低耦合。
层次图,HIPO图,数据流图
8.详细设计
程序的蓝图(略)
9.实现
编码和测试统称为实现。
测试的方法:
黑盒测试:不考虑程序的内部结构,测试程序功能能否正常使用。
白盒测试:知道程序的内部工作,检查是否按照规格说明书的规定正常进行。
测试过程:
单元测试、
集成测试、(重点) 主要采用渐增式测试方法,每次增加一个模块测试 策略:自顶向下和自底向上
自顶向下:从主控制模块开始,沿着程序的控制层次向下移动,逐渐把各个模块结合起来。有深度优先或宽度优先策略
缺点:当测试高层次需要低层次上的数据时,由于存根程序替代了低层次的模块,导致数据不能自下而上流。有两种方法解决:一、推迟这部分的测试,等需要低层次的模块加进来后再测试这部分。二、用自底向上的方法组装软件。
自底向上:把底层模块组成实现某个特定功能的族,写一个驱动程序,协调测试数据的输入和输出,测试后去掉驱动程序,沿软件结构自下向上移动,形成更大的子功能族。
缺点:不能早期发现上层模块的接口错误,并且不能早期实现和验证系统的主要功能。
改进:混合使用两种策略,上层的用自顶向下,下层模块用自底向上。
回归测试:重新执行已经做过的测试的某个子集,保证程序的变化没有带来非预期的副作用。
确认(验收)测试
测试后进行调试的方法:
蛮干法:让计算机自己寻找错误,在程序中到处写上输出语句。。。。最低效的方法。
回溯法:沿程序的控制流回溯追踪分析程序的源代码直到找出错误的原因为止。
原因排除法:对分查找法、归纳法、演绎法。向同行求助。
10.维护
维护是软件生命周期的最后一个阶段,也是持续时间最长,代价最大的一个阶段。软件工程学的主要目的就是提高软件的可维护性,降低维护的代价。
影响因素:可理解性,可测试性,可修改性,可移植性和可重用性。(面向对象的软件技术是目前最成功的软件重用技术)
文档:用户文档和系统文档。与程序代码同时维护。
二、面向对象方法学(真正的重点)
1.传统方法学在应对大项目开发时,很少取得成功。20世纪90年代,面向对象方法学已经成为人们开发软件时首选的范型。
使用UML的类图建立对象模型(最基本、最重要、最核心),使用数据流图或UML的用例图建立功能模型,使用UML的状态图建立动态模型。(难怪UML不进行纸质考试,只交实验报告,应该都放在这里考了)
2.OOA面向对象分析
分析=理解+表达+验证
5个层次:主题层、类与对象层、结构层、属性层、服务层。显示细节越来越多。
大致分析顺序:寻找类与对象、识别结构、识别主题、定义属性、建立动态模型、建立功能模型、定义服务。
下面是一个ATM机的例子。
加油呀!!~~期末必考~~~需求陈述有生活常识应该就知道啦。。。。略
确定类与对象:
非正式分析法
把需求陈述的名词作为类与对象的候选者,形容词作为确定属性的线索,动词作为服务(操作)的候选者。有些需求陈述里没有提到的,还赢根据该知识领域的相关内容把隐含的类与对象提取出来。
筛选,删除不必要的类和对象↓
冗余(表达相同信息的类只留一个最富有描述力的)
无关(与系统无关的类与对象去掉)
笼统(有更具体的名词对应它所暗示的事务,去掉)
属性(有些名词实际上在描写其他对象的属性)当然,如果某个属性有很强的独立性,也应该把它作为类
操作(即可作为名词又可作为动词的词,慎重考虑是作为类还是作为类中的操作)本身具有属性的操作,应作为类和对象。
实现(去掉仅和实现有关的类和对象)在设计和分析的阶段再考虑它们。
确定关联
把动词短语初步定为关联候选项。
筛选:删除不必要的关联↓
已删除的类之间的关联
与问题无关或应在实现阶段考虑的关联
瞬间事件的关联(如果动作表述隐含了问题域的某种基本结构,则应该用适当的动词词组重新表示这个关联
三元关联(分解成二元关联)
派生关联(去掉可以用其他关联定义的冗余关联)
完善:
正名:使名字更明确
分解:为了适用于不同的关联,必要时应该分解以前确定的类与对象
补充:分解类后,应及时补充关联
标明重数:(粗略就行)
确定属性
误把对象当成属性
误把关联类的属性当成一般类的属性
误把限定词当成属性(限定词:在类旁边的小框框,使得与其他类的重数由多比多变成多比一或由一比多变成一比一。)
误把内部状态当成属性
过于细化
存在不一致的属性(类是简单而且一致的,如果得出一些看起来和其他属性毫不相关的属性,则考虑将该类划分为两个不同的类)
识别继承(泛化)关系
自底向上 归纳
自顶向下 演绎
反复修改
建立动态模型
编写正常脚本和异常脚本(描述用户或其他外部设备与目标系统的交互过程)
画事件序列图
画状态图
状态图描写事件与对象状态的关系。当对象接受事件(序列图上的事件)以后,状态将会发生转变。仅考虑具有重要交互行为的类。
建立功能模型
功能级数据流图
定义服务
常规行为:分析阶段任务,类中的每个属性都是可以读写的,但是无需显示用服务定义出来。
从事件中导出的操作:由状态图发往该对象的事件必须有接受该事件消息的操作。
与数据流图中处理框相应的操作:数据流图中的每个处理框都与一个或多个对象上的操作对应。
利用继承减少冗余操作
3.OOD面向对象设计
准则:模块化、抽象、信息隐藏、弱耦合、强内聚、可重用
软件重用:
代码重用:源代码剪贴、源代码包含、继承
设计结果的重用:把一个应用系统移植到完全不同的软硬件平台上
分析结果重用:重用某个系统的分析模型
类构件(被重用的类)
实例重用、继承重用、多态重用
系统分解
系统的主要成分称为子系统。如编译器划分的六个子系统。尽量减少子系统之间彼此的依赖性。
子系统之间两种交互方式:
客户-供应商关系(client-supplier) 客户调用供应商,必须了解供应商的接口
平等伙伴关系(peer-to -peer) 每个系统之间都可互相调用。更复杂和出现更易出现设计错误。
组织系统的两种方案
层次组织 :底层组织相当于供应商,上层相当于客户
块状组织:若干个相对独立弱耦合的子系统垂直分布
常常将两者混合。
设计子系统。。。OMG,相当于总体设计(问题域、人机交互、任务管理、数据管理)
4.OOP面向对象实现
编码和测试
测试
面向对象的单元测试:
面向对象的集成测试:—->基于线程的测试:把相应系统的一个输入或一个事件所需要的那些类集成起来。分别集成并测试每个线程。同时用回归测试保证没有副作用。
——>基于使用的测试:首先测试几乎不适用服务器的类(独立类),再测试使用独立类的下一个层次的类(依赖类)再一个层次一个层次测试下去。
面向对象的确认测试:设计确认测试用例
昨天加今天整整两个上午,终于把这本书的重要内容预习完啦。。。。学到好多新名词,以后看到了就不会觉得有陌生的恐惧感啦~嘻嘻。不过应付考试,还得刷一天题目。