杂记
高内聚:尽可能类的每个成员方法只完成一件事(最大限度的聚合); 低耦合:减少类内部,一个成员方法调用另一个成员方法。
降低耦合度的方法
1、少使用类的继承,多用接口隐藏实现的细节。 Java面向对象编程引入接口除了支持多态外, 隐藏实现细节也是其中一个目的。
2、模块的功能化分尽可能的单一,道理也很简单,功能单一的模块供其它模块调用的机会就少。(其实这是高内聚的一种说法,高内聚低耦合一般同时出现)。
3、遵循一个定义只在一个地方出现。
4、少使用全局变量。
5、类属性和方法的声明少用 public,多用 private 关键字。
6、多用设计模式,比如采用 MVC
的设计模式就可以降低界面与业务逻辑的耦合度。
7、尽量不用“硬编码”的方式写程序,同时也尽量避免直接用 SQL
语句操作数据库。
8、最后当然就是避免直接操作或调用其它模块或类(内容耦合);如果模块间必须存在耦合,原则上尽量使用数据耦合,少用控制耦合,限制公共耦合的范围,避免使用内容耦合。
增强内聚度方法
1、模块只对外暴露最小限度的接口,形成最低的依赖关系。
2、只要对外接口不变,模块内部的修改,就不得影响其他模块。
3、删除一个模块,应当只影响有依赖关系的其他模块,而不应该影响其他无关部分。
软件工程学概述
没有银弹:一个典型的失败的产品,IBM 360 System
软件危机
软件维护工作以吃惊的比例耗费资源,许多程序的个体化特效使得它们最终成为不可维护的 ==> 软件危机
软件危机是指在计算机软件的开发和维护过程中所遇到的一系列严重的问题。几乎所有软件都不同程度地存在危机。
软件危机包含下述两个方面:
- 如何开发软件,以满足对软件日益增长的需求。
- 如何维护数量不断膨胀的已有软件。
软件危机的典型表现
- 对软件开发的成本和进度的估计常常不准确。【人和月是否可以交换?单纯的增加人数不一定可以提高开发效率,只有当这些功能模块相互独立,没有关联时,增加人手可以提高开发效率】
- 人是指开发人员;
- 月是指软件开发的时间单位。
- 一个工程师一个月的开发效率记为一个人月。
- 用户对“已经完成”的软件系统不满意的现象经常发生。用户和开发人员直接的交流不充分,开发人员对用户要求只有模糊的了解。
- 软件产品的质量往往靠不住。
- 软件常常是不可维护的,很多程序的错误是非常难改正。
- 软件通常没有适当的文档资料。
产生软件危机的原因
- 与软件本身的特性有关。
- 与软件开发与维护的方法不正确有关
- 软件开发过程的进展情况较难衡量,软件质量也难以评估。
- 规模大,程序的复杂性随着规模的增大呈指数上升。
- 在规定时间内,由多人开发出一个高质量的大型软件系统,是一个很复杂的问题。涉及许多技术。如人员的分配,技术问题,分析,设计和版本的迭代。
程序只是完整软件的一部分。一个完整的软件产品,应包含程序,文档和数据等成分。不能只注重程序本身,还要重视其他的配置。同时,在不同的开发时期进行修改要付出的代价事不同的。早期引入的变动成本较小,越到后期引入变动成本越高。
由于软件产品的使用周期很长,且不会想硬件一样自然损耗,软件的维护也显得格外重要。在漫长的使用时间中,要能及时改正发现的错误。
软件工程
定义
软件工程事指导计算机软件开发和维护的一门工程学科。把经过时间验证而证明正确的管理技术和当前的优秀技术方法结合起来,以经济地开发出高质量地软件并有效地维护它【指导计算机软件开发和维护。用成熟地管理技术和当前优秀地技术方法,经济高效地开发出高质量的软件并有效维护它】
本质特性
- 关注大型程序的构造
- 中心课题事控制复杂性
- 软件经常变化,要考虑其可扩展性
- 开发效率和重要
- 和谐合作是关键
- 软件是为用户而制作的,需要可以有效的支持它的用户
软件工程方法学
在软件生命周期全过程中使用的一整套技术方法的集合称为方法学。
软件工程方法学包括三个要素:方法、工具、过程
- 方法:完成软件开发的各项任务的技术方法,回答怎样做
- 工程:为运用方法而提供的自动的或半自动的软件工程支持环境
- 过程:为了获得高质量的软件所需要完成的一系列任务的框架,规定了完成各项任务的工作步骤。
传统方法学:使用结构化技术来完成软件开发的各项任务。【基本思想:把一个复杂问题的求解过程分阶段进行,而且这种分解是自顶向下,逐层分解,使得每个阶段处理的问题都控制在人们容易理解和处理的范围内。】
面向对象方法学:把面向对象的思想应用于软件开发过程中,指导开发活动的系统方法,对象是由数据和容许的操作组成的封装体,与客观实体有直接对应关系,一个对象类定义了具有相似性质的一组对象。【基本思想:尽可能模拟人类习惯的思维方式,使开发软件的方法与过程尽可能接近人类认识世界、解决问题的方法与过程, 也就是使描述问题的问题空间与实现解法的求解空间在结构上尽可能一致】
对比
- 结构化方法的基本单位是模块。
- 面向对象方法的基本单位是对象。
软件生命周期
由软件定义,软件开发,运行维护三个时期组成
软件定义
任务:确定软件开发工程必须完成的总目标;确定工程的可行性;系统必须完成的功能;估计完成工程需要的资源和成本,指定对于的进度表。
软件开发
任务:设计和实现前一时期定义的软件
通常由四个阶段组成:总体设计;详细设计;编码;单元测试;综合测试
运行维护
使软件持久地满足用户的需要。
软件生命周期阶段
问题定义
要解决的问题是什么
可行性研究
对于该问题是否有可行的解决办法
需求分析
不具体地解决问题,而是准确地确定“为解决这个问题,目标系统必须做什么”,主要是确定目标系统必须具备那些功能。
总体设计【概要设计】
该如何实现目标系统;设计程序的体系结构。确定程序由那些模块组成以及模块间的关系
详细设计
把解决方法具体化;该如何具体地实现这个系统。详细设计也成为模块设计。在这个阶段详细地设计每个模块,确定实现模块功能所需要地算法和数据结构
编码和单元测试
写出正确的容易理解的、容易维护的程序模块,并仔细测试编写出每一个模块。
综合测试
通过各种类型的测试使软件达到预定的要求【集成测试;验收测试】
软件维护
通过各种必要的维护活动使系统持久化地满足用户地需求
软件过程【开发模型】
概述
常见的软件过程模型
- 瀑布模型:规定了各项软件工程活动,【包括:制定软件项目计划,进行需求分析和定义,软件设计,程序编码,测试及运行维护】并且规定了它们自上而下,相互衔接的固定次序,如同瀑布流水,逐级下落
- 快速原型模型:快速建立起可在计算机上运行的程序,让用户试用,再根据用户的试用反馈快速地修改原型系统。
- 增量模型:把软件产品作为一系列的增量构建来设计、编码、集成和测试。
- 螺旋模型:
- 边做边改模型:
- 喷泉模型:
瀑布模型
瀑布模型规定了各项软件工程活动,【包括:制定软件项目计划,进行需求分析和定义,软件设计,程序编码,测试及运行维护】并且规定了它们自上而下,相互衔接的固定次序,如同瀑布流水,逐级下落
优点
可强迫开发人员采用规范地方法;严格的规定了每个阶段必须提交文档;要求每个阶段交出的所有产品都必须经过质量保证小组的仔细验证。
缺点
在把软件交付给用户前,用户只能通过文档来了解产品。由于双方的交流存在偏差,会导致用户得不到满意的铲平。
快速原型模型
快速建立起可在计算机上运行的程序,让用户试用,再根据用户的试用反馈快速地修改原型系统。
优点
可以得到比较良好的需求定义,容易适应需求的变化;有利于开发与培训的同步;费用低、开发周期短且对用户更友好。
缺点
客户与开发者对原型理解不同; 准确的原型设计比较困难; 不利于开发人员的创新。
增量模型
把软件产品作为一系列的增量构建来设计、编码、集成和测试。
优点
优点是人员分配灵活,刚开始不用投入大量人力资源;能在较短时间内向用户提交已完成的部分功能;且这样不断地给用户一小部分功能,可以给用户充足地时间学习和适用这个系统。
缺点
并行开发构件有可能遇到不能集成的风险,软件必须具备开放式的体系结构;变化的能力大大优于瀑布模型和快速原型模型,但也很容易退化为边做边改模型,从而是软件过程的控制失去整体性
螺旋模型
使用原型及其他方法来尽量降低风险。
优点
灵活性,可以在项目的各个阶段进行变更.计算变得简单容易;客户始终参与每个阶段的开发,保证了项目不偏离正确方向以及项目的可控性.
缺点
需要具有相当丰富的风险评估经验和专门知识,在风险较大的项目开发中,如果未能够及时标识风险,势必造成重大损失;会增加开发成本,延迟提交时间。
适用范围
螺旋模型只适合于大规模的软件项目。
可行性研究
概述
可行性分析的目的是为了确定问题是否值得去解决!
分类
- 技术可行性:使用现有技术可以实现这个系统吗?
- 经济可行性:这个系统的经济效益能够超过它的开发成本【应该说:这个系统带来的经济效益值得我去做吗】
- 操作可行性:系统的操作方式在这个用户组内行得通吗?【用户是否可以适应使用这个系统】
需求分析
概述
了解用户需求,准确回答系统必须做什么!对目标系统提出完整,准确,清晰,具体的要求
在可行性研究阶段,粗略地了解了用户的需求,甚至提出了一些可行的方案,但是忽略了许多细节,并没有准确回答系统必须做什么这个问题!因此不能替代需求分析!
确定对系统的综合要求
功能需求
系统必须提供的服务。通过需求分析,划分出系统必须完成的所有功能。
性能需求
系统必须满足的定时约束或容量约束。通常包括响应速度,信息量速率,主存容量,安全性等方面
可靠性和可用性需求
可靠性:如每月出错的次数不能太多。
可用性:确保系统绝大多数时间是可以正常运行的。
出错处理需求
系统出现错误时该如何处理,给用户怎样的反馈。
接口需求
描述应用系统与它的环境通信的格式。
约束
设计和实现系统时应遵守的限制条件
逆向需求
说明软件不应做什么
将来可能提出的要求
那些不属于当前系统的开发范畴,但是以后可能会提出这类要求,对系统进行扩展。
总体设计
概述
概况地说,系统应该如何实现。
总体设计又称为概要设计或初步设计。可以站在全局高度上,花较少地成本,从较抽象地层次分析对比多种可能的实现方案和软件结构,从中选择出最佳方案和最合理的软件结构,从而用较低成本开发出质量较高的软件系统。【从全局的观点出发,对比各种可能的方案,选出最佳的最合理的软件结构,减少成本!】
设计过程
总体设计过程由两个主要阶段组成:系统设计阶段,确定系统的具体实现方案;结构设计阶段,确定软件结构。
步骤
- 设想供选择的方案
- 选取合理的方案
- 推荐最佳方案
- 功能分解
- 设计软件结构
- 设计数据库
- 制定测试计划
- 书写文档
- 审查和复审
详细设计
确定应该怎样具体地实现所要求地系统。经过这个阶段的设计工作,应该得出对目标系统得精确描述,从而在编码阶段可以把这个描述直接翻译称用某种程序设计语言书写得程序。【设计出程序的蓝图,程序员根据蓝图去书写程序】
实现
概述
实现包括编码和测试。测试应该横跨编码的整个时期,无论如何强调测试都不为过!
编码:把程序设计的结果变成代码。
测试的重要性:无论如何强调软件测试的重要性和它对软件可靠性的影响都不为过。
测试的目的:在软件投入生产性运行之前,尽可能多发现软件中的错误。软件测试是保证软件质量的关键步骤,是对软件规格说明,设计和编码的最后复审。
软件测试占比:软件测试的工作量往往占总工作量的 40% 以上!
测试总结:测试是为了发现软件的错误,最终目的还是为了保证开发的质量符合用户的要求!
编码
- 选择程序设计语言
- 确定编码风格
- 统一编码风格,便于阅读和维护。
首先,选择合适的语言来开发系统。不同的语言擅长的场景是不一样的,开发效率也不一样。选择一门合适的语言即可减少开发难度,又可以提升编码效率。
其次,规定编码风格。统一编码风格可以让整个系统看起来想一个人写的,风格统一,便于后期的阅读,修复和扩展功能。
再者,为代码添加恰当的注释,程序的开发一般周期性较长,即便是自己写的代码,长时间不去看也会很陌生。为代码添加恰当的注释可有效避免这种问题。
避免复杂逻辑的书写,尽量将其拆分为多个简单逻辑,有利于阅读和调试。
对输入输出数据进行合法性校验,避免被攻击。
软件测试基础
软件测试,竭力证明程序中有错误,从而完善程序,满足用户需求。软件测试应从小规模开始,这样方便定位错误!
软测目标
发现程序中的错误。
成功的测试是发现程序中未被发现过的错误。
软测准则
所有测试都应该追溯到用户需求【为用户的需求而服务】
应在测试之前就制定出测试计划
把 pareto
原理应用到软件测试中
软件测试-Pareto 法则(8:2)
pareto
含义:【这和计组的那个 RISC & CISR 一样】
-
80% 的软件缺陷生存在软件 20% 的空间里
-
20% 的缺陷消耗 80% 的维护费用
-
20% 的原因导致 80% 的缺陷
应该先从小规模测试开始,并逐步进行大规模测试。
穷举测试是不可能的。把执行路径都检查一遍的测试是不可能的。即便是中等规模的程序,其执行路径的排列数,输入数据的各种组合,也十分庞大。受限于时间、人力以及其他资源的限制,不可能执行每个可能的路径。【只能证明程序中有错误,无法证明无错误】
为达到最佳测试效果应雇佣专业的测试人员进行测试!程序员自己对自己写的程序有谜之自信,很难发现那些错误。
测试方法
黑盒测试
测试每个功能是否都能正常使用
将程序看成不能打开的黑盒子,不考虑程序内部结构和特性的基础上通过程序接口进行测试。黑盒测试又称为功能测试。
白盒测试
知道内部工作过程,可以通过测试来检验产品内部动作是否按照规格说明书的规定正常运行
白盒测试下,软件程序被看做是一个打开的盒子,测试者完全知道程序的结构和处理算法。测试者按照程序内部的逻辑测试程序,检测程序中的主要执行通路是否都能按预定要求正确工作。
测试步骤
直接测试一个完整的系统是不切实际的,测试过程应分步骤进行。
- 模块测试:对于独立的,与其他模块无依赖关系的模块,可作为一个单独的实体来进行测试。模块测试又称为单元测试,保证每个模块作为一个单元都能正常运行。这个测试步骤中所能发现的往往是编码和详细设计的错误。
- 子系统测试:把经过单元测试的模块放在一起形成一个子系统来测试。模块相互间的协调和通信是这个测试过程中的主要问题。
- 系统测试:把经过测试的子系统装配成一个完整的系统来测试。这个过程中不仅应该发现设计和编码的错误,还应该验证系统确实能提供需求说明中的功能。这个测试步骤发现的往往是软件设计中的错误,也可能发现需求说明中的错误。
- 验收测试:把软件系统作为单一的实体进行测试。确保系统的确可以满足用户需求。这个步骤发现的往往是系统需求说明书中的错误。也称为确认测试。
- 平行运行:如果有旧系统的花,比较新开发出的系统和旧系统的处理结果。可以让用户有一段熟悉新系统的时间。
UML
用例视图–静态建模
定义了系统的外部行为,是最终用户、分析人员和测试人员所关心。该视图定义了系统的需求。
执行者:描述与系统交互的人或物,代表外部实体【如用户或其他软件系统】
用例的粒度能粗就不要细。
执行者之间的关系:泛化关系【一般和特殊的关系。符号化表示为 特殊执行者指向一般执行者】
用例之间的关系:
-
关联关系:可以 1 对 1,1 对多等
-
包含关系:一个基本行为包含另一个基本行为。
-
扩展关系:不允许随便扩展,只能在指定的扩展点进行扩展。【扩展的指向基本的】
-
泛化关系:一般类和特殊类之间的继承关系
类图对象图–静态建模
类图
表达类与类之间的静态关系;属性的可见性:公有(+) 私有(-) 保护(#)
对象图
显示了一组对象和他们之间的关系,使用对象图来说明数据结构
包
设计视图
描述了支持用例视图中规定的功能需求的逻辑结构。
实现视图
描述构造系统的物理组件。
进程视图
包括形成关于并发和同步机制的进程和线程。
部署视图
部署视图描述物理组件如何在系统运行的实践环境中分布【这个组件在系统的那个硬件上运行】。