软件设计理论(转)

    技术2026-08-25  13

    (2010-11-30 20:16:48) 转载 把软件开发与你所熟知的事情联系在一起,从而使你对其有更深刻的理解(隐喻).特别是 建筑 将软件设计和建造房子联系起来考虑会有非常深的理解. 软件设计基本上分下面几步: 1.系统描述,问题定义.       知道自己想要个什么样的东西.比如在建房子前要知道自己是想要个几居室的,还是别墅,或者只是想给自家的小狗做个狗窝. 2.需求分析.       知道这个东西的详细要求.软件是产品,是为用户服务的.一定要考虑用户的需求.就象在造房子时要先知道一些详细的参数.多宽,多高.门在什么地方等.如果等墙都做起来了再改,那就麻烦了.就象开发中一样.先不管需求,自己做自己的,等做完后发现别人想要的不是那个事.要时候注意到软件是给业务服务的.它是一个产品,用户的需求是第一位的. 3.结构分析,实现计划.       框架搭建,模块划分,核心类库完成.这些是程序级别的工作.任务的细分及工期制定,任务完成追踪等这是项目管理级别的工作.就象做房子时工头会进行划分,哪些人和水泥,哪些人搬砖等.要让每个人都达到最高效率.同时不能因为一个人而影响整个工程. 4.详细设计.       选择某种或某些语言来实现需求中的功能.语言只是一种工具.所以在此步要考虑. 5.编码,创建及实现       大部分初级程序员都只接触到此步.但实际上此步在项目听地位并不是象他们想的那样重要.他们认为:这个软件就是我们做出来的.而实际上他们只不过是用程序将别人的想法表达出来而已. 6.系统集成       将各子系统,模块结合起来. 7.单元测试       单元测试一般会归到编码中一起执行. 8.系统测试       整体测试,有很多.如安全性测试,性能测试,并发压力测试等. 9.维护       数据维护,功能更新等. ************************************************************** 需求分析: · 系统的所有输入都定义了吗?包括它们的来源、精度、取值范围和频率? · 系统所有的输出都定义了吗?包括它们的目标、精度、取值范围、频率和格式? · 所有的硬件与软件接口都定义了吗? · 所有的通信界面都定义了吗?包括握手、错误检查以及通信约定? · 是否从用户的观点出发,定义了所有必要操作的反应时间? · 是否定义了时间问题,如处理时间、数据传输率以及系统吞吐能力? · 是否对用户所要求完成的任务都作出了规定? · 每项任务所需用到和产生的数据都规定了吗? · 规定保密级别了吗? · 规定可靠性了吗?包括软件出错的后果、在出错时要保护的至关重要的信息、以及错误测试和恢复策略。 · 规定所需最大内存了吗? · 所需最大存储容量规定了吗? · 对系统的维护性是否作出了规定?包括系统对运行环境、精度、性能以其与其它软件的接口等方面变化的适应能力规定了吗? · 是否规定了相互冲突的设计之间的折衷原则,例如,在坚固性与准确性之间如何进行折衷? · 是否制定了系统成败的标准? 关于需求的完善性 · 在开发开始前暂时得不到的信息是什么?是否规定了不够完善的区域? · 需求定义是否已经完善到了可以成为软件标准的地步? · 需求中是否有哪一部分令你感到不安?有没有根本不可能实现,而仅仅为了取悦老板和用户才加进来的内容? 关于需求的质量 · 需求是否是用用户的语言制定的?用户也这样认为吗? · 需求中是否每一条之间都尽量避免冲突? · 需求中是否注意了避免规定设计工作? · 需求在详细程度方面是否保持了一致性;有没有应该更详细些的需求?有没有应该更简略些的? · 需求是否明确得可以分为一些独立的可执行部分,而每一部分又都很明了? · 是否每一条都与问题和答案相关?是否每一条都可以追溯到产生它的环境中? · 是否每一条需求都可以作为测试依据?是否可以针对每一条进行独立测试以确定是否满足需求? · 是否对可能的改动作出了规定?包括每一改动的可能性? 设计软件结构时要考虑的因素: 变动策略 变动产生的原因可能是由于反复无常的数据结构,也可能是由于文件格式和系统功能改变,新的性能等而引起的。这些变动有时是为了增加新的能力以便强化功能,也有时是版本增加而引起的。所以结构设计所面临的主要挑战便是增强系统的灵活性,以便容纳这类变动。 购买而不是建造的决定 如果计划中要求使用已有的程序,那它就该指出如何使这些重新被使用的软件适应新的需求,而且它应该证明这个软件可以通过改动来满足新的需求。 主要的数据结构 结构设计应该给出使用的主要文件、表和数据结构。同时,还应给出考虑的替代方案并评审作出的选择. 如果一个程序使用了数据库,那么结构中应该规定这个数据库的组织形式和内容。最后,应该遵循数据守恒定律:每一个进入的数据都应该出去,或者与其它数据一道出去,如果它不出去,那它就没有必要进来。 关键算法 如果结构设计依赖于某一特定算法,那它应该描述或指出这一算法。同主要数据结构一样,结构设计中也应该指出考虑过的算法方案,并指出选中最终方案的原因。比如,如果系统的主要部分是排序,而结构设计中又指定了排序方式是堆排序,那它就要说明为什么采用堆排序的方法,以及未采用快速排序或插入排序的理由。如果是在对数据作出某种假定的基础上才选中堆排序的,那就该给出这个假定。 主要对象 在面向对象的系统中,结构中应指出要实现的主要对象,它应该规定每一个对象的责任并指出每个对象之间是如何相互作用的。其中应包括对于排序层次、状态转换和对象一致性的描述。 通用功能 除了特定程序的特定功能,绝大多数程序中都需要几种在软件结构中占有一席之地的通用功能。 用户界面 有时用户界面在需求定义阶段便已经规定了。如果没有的话,那就应该在结构设计中作出规定。结构中应该定义命令结构,输入格式和菜单 输入/输出 结构中应规定采用向前看、向后看还是当前规则的查询方式。同时,还应该指出在哪个层次上检查输入/输出错误,是在区域层次、记录层次还是在文件层次上。 内存管理 内存管理是结构设计中应该处理的另一个重要部分,结构中应该对正常和极端情况下所需要的内存作出估计。例如,如果你正在写数据表,那么结构就应估计其中每一个单元所需的内存。它还应估计正常表格和最大表格所需要的内存。在简单情形下,这种估计应表明内存在某项功能的实现环境中是正常的 字符串存储 在交互式系统中,字符串存储也应在结构设计阶段予以重视。在这种系统中,往往包含了大量的提示、帮助信息和状态显示。应该估计被字符串所占用的内存。如果程序是商用的,那么,结构中应该考虑到典型的字符串问题,包括字符串的压缩,不必修改代码即可保持字符串,以及保证在译成外文时对代码的影响将是最小的。结构设计可以决定字符串的使用方法,是编码在程序中,还是把它保存在数据结构中。是需要时通过存取子程序调用,还是把它存在一个源文件中,结构设计应该指明采用哪种方法及其原因。 错误处理 程序中有 90%的代码是为了应付例外的错误处理或者内务处理而编写的,就是说仅有10%的代码才是处理正常情况的 1.提醒用户发现了错误 2.错误测试是主动的还是被动的?系统可以积极地预防错误,如通过检验用户的输入是否合法,当然也可以消极地在无法回避它们时才做出反应.例如,用户的一系列输入产生了溢出,你可以清除,也可以滤除信息。同样,无论哪种方案,都要提醒用户。 3.程序是怎样对付错误的?一旦测试出错误,程序可以立刻抛弃产生错误的数据,也可以把它当作错误而进入错误处理状态,还可以等到全部处理完毕后再通知用户数据有误。 4.结构设计中应建立一套处理错误信息的约定.如在页面上是提示,还是弹出窗口等. 5.在程序中,应该在哪一个层次上处理错误呢?你可以在发现的地方立即处理,也可以把它交给一个错误处理子程序去处理,或者交给更高层次的子程序处理.是自己报错,还是往上抛.等. 6.每一个模块检验输入数据合法性的责任级别有多高?是每一模块仅检验它自己的数据,还是由一级模块来检验整个系统的数据?是否每个层次上的模块都可以假定输入其中的数据是合法的? 坚固性 坚固性是指在发现错误后,一个系统继续运行的能力 结构中作出每一个决定的动机都要阐明清楚。要当心“我们过去一直是这么干的”的理由。 结构的目标应该清楚地说明。一个以可变性为首要目标的结构设计可能与一个以性能为首要目标的结构设计差之千里,虽然二者的功能可能是完全一样的。 结构设计检查表 · 软件的总体组织形式是否清晰明了?包括对于结构设计的总体评论与描述。 · 模块定义是否清楚?包括它们的功能及其与其它模块的接口。 · 需求定义中所提出的所有功能,是否有恰当数量的模块覆盖? · 结构设计是否考虑了可能的更改? · 是否包括了必要的购买? · 是否阐明了如何改进重新启用的代码来满足现在的结构设计需求? · 是否描述并验证了所有主要的数据结构? · 主要数据结构是否隐含在存取子程序中? · 规定数据库组织形式和其它内容了吗? · 是否说明并验证所有关键算法? · 是否说明验证所有主要目标? · 说明处理用户输入的策略了吗? · 说明并验证处理输入/输出的策略了吗? · 是否定义了用户界面的关键方面? · 用户界面是否进行了模块化,以使对它所作的改动不会影响程序其它部分? · 是否描述并验证了内存使用估算和内存管理? · 是否对每一模块给出了存储空间和速度限制? · 是否说明了字符串处理策略?是否提供了对字符串占用空间的估计? · 所提供的错误处理策略是不是一致的? · 是否对错误信息进行了成套化管理以提供一个整洁的用户界面? · 是否指定了坚固性级别? · 有没有哪一部分结构设计被过分定义或缺少定义了?它是否明确说明了? · 是否明确提出了系统目标? · 整个结构在概念上是否是一致的? · 机器和使用实现的语言是否顶层设计依赖? · 给出做出每个重要决定的动机了吗? · 你作为系统实现者的程序员,对结构设计满意吗? 编码阶段: · 验证基础工作已经完成,可以进行创建工作 · 设计和编写子程序与模块 · 创立数据类型并命名变量 · 选择控制结构并组织语句块 · 找出并修正错误 · 评审其它小组的细节设计和代码,同时接受其它小组评审 · 通过仔细地格式化和征集意见改进编码 · 对分别完成的软件单元进行综合 · 调整编码使其更小、更快 定义: · 创建活动是总体设计和系统测试之间承上启下的工作。 · 创建活动主要包括:详细设计、编码、调试和单元测试。 如前所述,在编码前还有很多步骤要做.一种较好的设计模式叫" 增量开发". 在增量开发中,你首先设计系统可以运行的最简单版本。它甚至可以不接受实际数据输入,或者对数据进行处理。它也可以不产生输出,只需要成为一个坚实的骨架结构,以便能承受将要在它之上发展的真实系统. 而且前期准备越充足后期风险越小.就象在建筑中: 多用 10%的材料来加强结构总比一幢大楼坍塌要好得多 编码时基本数据类型注意事项: 常数 1.避免"奇异数".“奇异数”指的是出现在程序中间的不加解释的常数。如100或47524。如果你所用的语言支持命名常量的话,那就用命名常量来代替它。如果无法使用命名常量的话,应考虑使用全局变量。 2.在需要时可以使用常数“0”或“1”。"0"或"1"往往被用来增加或减少循环变量的值,也用于数组的第一个元素下标或循环变量的初始值 3.采取预防被"0"除的措施。每当你在程序中使用了除号(大多数语言中都用"/"表示)时,都要考虑除数是否有可能是零。如果存在这种可能性的话,应加入防止被“0”除的代码 4.明显进行类型转换。当程序中有不同类型间的转换时,要确保这种转换是明显的.在C中,可以用:x = a + (float)i 5.避免混合类型比较。如果x是浮点数而i是一个整型数,那么以下检验:if ( i=x ) then 几乎可以认定是不会起作用的 整型数 1.检查整型相除.当你使用的是整型数时,7/10并不等于0.7,它等于0.在整型算法中10*(7/10)却等于0,因为(7/10)等于0,解决这个问题最简单的办法是调整计算顺序,如上例的表达式可以改写为:(10*7)/10 2.检查整型是否溢出.在进行整型加法或乘法运算时,应明确可能的最大整型数 浮点数 1.不要在数量级相差太大的数之间进行加减运算.假设变量都是4个字节的浮点变量,那么1,000,000.00+0.01的结果很可能仍然是1,000,000.00而不是1,000,000.01,因为这里的浮点变量只有4个字节,因而在结果中0.01事实上是无效数字。同样,5,000,000.02-5,000,000.01的结果也很可能是0.0而不是0.1. 2.避免相等比较.应该相等的浮点数事实上往往是不相等的。主要问题是:算法不同但结果应该相同的浮点数运算的结果事实上是不同的。例如,把0.l累加10次的结果很少是1.0 数组 1.确保所有的数组下标都没有越界. 2.把数组当作顺序性结构.建议决不要随机地对数组进行存取,用其元素以顺序存取的集合、堆栈或者队列来代替数组 原文链接:http://blog.sina.com.cn/s/blog_5f54f0be0100nod6.html
    最新回复(0)