软件设计规范
?概述 ??? 软件设计是把需求转化为软件系统的最重要的环节,系统设计的优劣在根本上决定了软件系统的质量。 ??? 在此,主要阐述软件系统设计的5个核心内容:体系结构设计、用户界面设计、数据库设计、模块设计、数据结构和算法设计。旨在帮助开发人员搞清楚“设计什么”以及“如何设计”。 ??? 一般把设计过程划分为两个阶段:概要设计阶段和详细设计阶段,如下所示: ??? *概要设计阶段的重点是体系结构设计。 ??? 体系结构 ??? 体系结构如同人的骨架。如果某个家伙的骨架是猴子,那么无论怎样喂养和美容,这家伙始终都是猴子,不会成为人。 ??? 由此可见,体系结构乃是系统设计的重中之重。 ??? 目前业界比较流行的软件结构模式有C/S(客户/服务器)、B/S(BROWSE/SERVER)、层次结构(上下级层次结构、顺序相邻的层次结构、含中间件的层次结构) ??? 体系结构设计原则 ??? ● 合适性 ??? 即体系结构是否适合于软件的“功能性需求”和“非功能性需求”。高水平的设计师高就高在“设计出恰好满足客户需求的软件,并且使开发方和客户方获取最大的利益,而不是不惜代价设计出最先进的软件。 ??? ● 结构稳定性 ??? 详细设计阶段的工作如用户界面设计、数据库设计、模块设计、数据结构与算法设计等等,都是在体系结构确定之后开展的,而编程和测试则是更后面的工作,因此体系结构应在一定的时间内保持稳定。 ??? 软件开发最怕的就是需求变化,但“需求会发生变化”是个无法逃避的现实。人们希望在需求发生变化时,最好只对软件做些皮皮毛毛的修改,可千万别改动软件的体系结构。如果当需求发生变化时,程序员不得不去修改软件的体系结构,那么这个软件的系统设计是失败的。 ??? 高水平的设计师应当能够分析需求文档,判断出哪些需求是稳定不变的,哪些需求是可能变动的。于是根据那些稳定不变的需求设计体系结构,而根据那些可变的需求设计软件的“可扩展性”。 ??? ● 可扩展性 ??? 可扩展性是指软件扩展新功能的容易程度。可扩展性越好,表示软件适应“变化”的能力越强。 ??? 可扩展性越来越重要,这是由现代软件的商业模式决定的: ??? *社会的商业越发达,需求变化就越快。需求变化必将导致修改(或者扩展)软件的功能,现代软件的规模和复杂性要比十年前的大得多(对比一下操作系统的变化就明白了),如果软件的可扩展性比较差的话,那么修改(或者扩展)功能的代价会很高。 ? ? ● 可复用性 ??? 由经验可知,通常在一个新系统中,大部分的内容是成熟的,只有小部分内容是创新的。一般地可以相信成熟的东西总是比较可靠的(即具有高质量),而大量成熟的工作可以通过复用来快速实现(即具有高生产率)。 ??? 可复用性是设计出来的,而不是偶然碰到的。要使体系结构具有良好的可复用性,设计师应当分析应用域的共性问题,然后设计出一种通用的体系结构模式,这样的体系结构才可以被复用。 ??? 用户界面设计 ??? 为了提高用户界面的易用性和美观程度,总结了十个设计原则。用于提高易用性的界面设计原则有8个: ??? *用户界面适合于软件的功能 ??? *合理的布局 ??? ● 用户界面适合于软件的功能 ??? 用户界面的合适性是指界面与软件功能相融洽的程度。软件的功能需要通过用户界面来展现,用户界面一定要适合于软件的功能,这是最基本的要求。界面的合适性既提倡外美内秀,又强调恰如其分。 ??? ● 容易理解 ??? 提高用户界面可理解性的一些规则如下: ??? *界面中的所有元素(如菜单、工具条等)没有错误,也不会让人误解。 ??? ● 风格一致 ??? 风格一致有两方面的含义: ??? (1)一个软件的用户界面中,同类的界面元素应当有相同的视感和相同的操作方式。例如命令按钮是最常见的界面元素,所有命令按钮的形状、色彩以及对鼠标的响应方式都是一致的。 ??? (2)同一类型软件的用户界面应当有一定程度的相似性。例如Microsoft公司的Office家族里有Word、Excel、PowerPoint、Outlook等软件,这些软件提供的“复制、剪切、粘贴”功能的操作方式都是相同的。 ??? ● 及时反馈信息 ??? 用户进行某项操作后,如果过了一会儿(几秒钟)用户界面一点反应都没有,这将使用户感到迷茫和不安,因为他不知道是自己操作错了还是软件的原因导致死机了。所以及时反馈信息很重要,至少要让用户心里有数,知道该任务处理得怎么样了,有什么样的结果。 ??? 例如下载一个文件,界面上应当显示“百分比”或相关数字来表示下载的进度,否则人们不知道要等待多少时间。如果某些事务处理不能提供进度等数据,那么至少要给出提示信息如“正在处理,请等待…”,最好是提供合适的动画,让用户明白软件正在干活、没有死机。 ? ● 出错处理? ??? 在设计用户界面时必须考虑出错处理,目的是让用户不必为避免犯错误而提心吊胆、小心翼翼地操作。常见的错误处理方式有: ??? *提供对输入数据进行校验的功能。当用户输入错误的数据时,及时提醒用户改正数据。 ??? ● 合理的布局 ??? 首先,界面的布局应当符合逻辑,最好能够与工作流程吻合。界面设计人员只有仔细地分析软件的需求,才能提取对界面布局有价值的信息。 ??? 其次,界面的布局应当整洁(整齐清爽)。界面元素应当在水平或者垂直方向对齐,行、列的间距保持一致。窗体的尺寸要合适,各种控件不能过分拥挤也不能过分宽松。要善于利用窗体和控件的空白,以及分割用的线条。 ??? ● 和谐的色彩 ??? 用户界面是否美观,主要取决于该界面的布局和色彩搭配。实现“合理的布局”相对比较容易一些,设计和谐的色彩太困难了,因为色彩的组合千变万化,并且人们对颜色的喜好也极不相同。 ??? 对于广大软件开发人员而言,虽然我们没有必要让普通软件的界面漂亮到Windows XP这种程度,但是掌握一些界面色彩的设计原则无疑是非常有益的。 ??? *如果不是为了显示真实感的图形和图像,那么应当限制一帧屏幕的色彩数目,因为人们在观察屏幕的时候很难同时记住多种色彩。 ??? ● 开发与平台无关的数据库应用程序 ??? 目前国际上应用最广泛的数据库系统有Oracle、DB2、Informix、Sybase和SQL Server。 ??? 这些数据库系统之间的激烈竞争即有好处又有坏处。竞争的好处是使数据库系统不断发展和完善,并且避免价格垄断。竞争的最大坏处是逼迫数据库厂商不断开发出独特的功能以吸引更多的用户,所以各个数据库系统的独特功能无法形成统一标准,导致用户难以开发出与平台无关的数据库应用程序,因为用户很难抵御数据库系统独特功能的诱惑。 ??? 读者也许会问:“结构化查询语言(SQL)难道不是数据库系统的标准吗?” ??? 是的,SQL是数据库系统的标准查询语言。可是数据库厂商提供了太多超出SQL标准的特色功能,使人们陷入了进退两难的境地: ??? *如果你想使程序与数据库平台无关,那么只能使用SQL,放弃各个数据库系统的独特功能。 ? ● 数据库性能优化问题? ??? 数据库设计的主要挑战是“高速处理大容量的数据”。如何优化数据库的性能是设计人员经常面临的问题。数据库性能优化主要有两种途径: ??? *优化表结构本身。例如对第三范式的表结构进行反规范化处理,允许表中存在冗余数据,从而减少多个表链接操作,达到提高性能的目的。 ??? 反规范化处理是指对第三范式的表进行修改,通过合并一些表,或者在表中创建冗余的列,从而减少表链接操作代价,达到提高性能的目的。要注意的是反规范化处理存在很大的负面影响:管理冗余数据很麻烦,如果冗余数据不同步的话,那么会发生数据错误这种严重的问题。 ??? 所以,对表进行第三范式的规范化处理是第一重要的,而反规范化处理则需谨慎考虑、不宜过多使用。“规范化处理”以及“反规范化处理”不是自相矛盾之举,而是性能优化的策略。 ??? 除了优化表结构之外,优化数据库的环境参数也能够提高数据库的性能。例如给服务器配置更快的CPU,增加内存。运行数据库是非常消耗内存的,内存对数据库性能影响比较大。由于现在市场上的内存条越来越便宜,所以为服务器配置足够多的内存恐怕是成本最低、难度最低、见效最快的性能优化方法。 ??? 在安装数据库系统时,要为系统指定“块大小”(一次物理读写操作所设计的字节数)。在创建表时,也要为表指定一定的空间。如果“块大小”和“表空间”与实际的数据存储不匹配的话,那么会产生许多磁盘碎片,这将降低数据库物理操作的性能。 ??? 能否有效地优化应用软件数据库的性能,主要取决于开发者对数据库系统的熟悉程度以及开发经验。 ??? ● 数据库安全问题 ??? 提高软件系统的安全性应当从“管理”和“技术”两方面着手。这里仅考虑技术手段(因为安全管理超出了软件工程范畴),一般原则如下: ??? *用户只能用帐号登陆到应用软件,通过应用软件访问数据库,而没有其它途径可以操作数据库。 ??? 模块设计 ??? 评价模块设计优劣的三个特征因素:“信息隐藏”、“内聚与耦合”和“封闭——开放性”。 ??? ● 信息隐藏 ??? 为了尽量避免某个模块的行为去干扰同一系统中的其它模块,在设计模块时就要注意信息隐藏。应该让模块仅仅公开必须要让外界知道的内容,而隐藏其它一切内容。 ??? 模块的信息隐藏可以通过接口设计来实现。接口是模块的外部特征,应当公开;而数据结构、算法、实现体等则是模块的内部特征,应当隐藏。一个模块仅提供有限个接口(Interface),执行模块的功能或与模块交流信息必须且只须通过调用公有接口来实现。如果模块是一个C++对象,那么该模块的公有接口就对应于对象的公有函数。如果模块是一个COM对象,那么该模块的公有接口就是COM对象的接口。一个COM对象可以有多个接口,而每个接口实质上是一些函数的集合。 ? ● 高内聚 ??? 内聚(Cohesion)是一个模块内部各成分之间相关联程度的度量。内聚程度从低到高大致划分为低端、中段和高端。模块设计者没有必要确定内聚的精确级别,重要的是尽量争取高内聚,避免低内聚。 ??? 顺序性内聚 功能性内聚 ??? 时序性内聚 过程性内聚 通讯性内聚 ??? 偶然性内聚 逻辑性内聚 ??? 低端… 中段… 高端… ??? 各种内聚类型的含义如下: ??? *偶然性内聚。如果一个模块的各成分之间的关系彼此松散(几乎无关),称为偶然性内聚。 ??? ● 低耦合 ??? 耦合(Coupling)是模块之间依赖程度的度量。内聚和耦合是密切相关的,与其它模块存在强耦合的模块通常意味着弱内聚,而强内聚的模块通常意味着与其它模块之间存在弱耦合。 ??? 耦合的强度依赖于以下几个因素:(1)一个模块对另一个模块的函数调用数量;(2)一个模块向另一个模块传递的数据量;(3)一个模块施加到另一个模块的控制的多少;(4)模块之间接口的复杂程度。 ??? 耦合程度从低到高大致划分为低端、中段和高端,如图3-16所示。模块设计应当争取“高内聚、低耦合”,而避免“低内聚、高耦合”。 ??? 印记耦合 控制耦合 ??? 公共耦合 内容耦合 ??? 非直接耦合 数据耦合 ??? 低端… 中段… 高端… ??? 各种耦合类型的含义如下: ??? *非直接耦合。模块之间没有直接的信息传递,称为非直接耦合。 ? 数据结构与算法设计 ??? 一般说来,数据结构与算法就是一类数据的表示及其相关的操作(这里算法不是指数值计算的算法)。从数据表示的观点来看,存储在数组中的一个有序整数表也是一种数据结构。算法是指对数据结构施加的一些操作,例如对一个线性表进行检索、插入、删除等操作。一个算法如果能在所要求的资源限制(Resource Constraints)范围内将问题解决好,则称这个算法是有效率(Efficient)的。例如一个资源限制可能是“用于存储数据的内存有限”,或者“允许执行每个子任务所需的时间有限”。一个算法如果比其它已知算法所需要的资源都少,这个算法也被称为是有效率的。算法的代价(Cost)是指消耗的资源量。一般说来,代价是由一个关键资源例如时间或空间来评估的。 ??? 毋庸置疑,人们编写程序是为了解决问题。只有通过预先分析问题来确定必须达到的性能目标,才有希望挑选出正确的数据结构。有相当多的程序员忽视了这一分析过程,而直接选用某一个他们习惯使用的,但是与问题不相称的数据结构,结果设计出一个低效率的程序。如果使用简单的设计就能够达到性能目标时,选用复杂的数据结构也是没有道理的。 ??? 人们对常用的数据结构与算法的研究已经相当透彻,可以归纳出一些设计原则: ??? 1) 一种数据结构与算法都有其时间、空间的开销和收益。当面临一个新的设计问题时,设计者要彻底地掌握怎样权衡时空开销和算法有效性的方法。这就需要懂得算法分析的原理,而且还需要了解所使用的物理介质的特性(例如,数据存储在磁盘上与存储在内存中,就有不同的考虑)。 ??? 2) 开销和收益有关的是时间——空间的权衡。通常可以用更大的时间开销来换取空间的收益,反之亦然。时间——空间的权衡普遍地存在于软件开发的各个阶段中。 ??? 3) 设计人员应该充分地了解一些常用的数据结构与算法,避免不必要的重复设计工作。 ??? 4) 数据结构与算法为应用服务。我们必须先了解应用的需求,再寻找或设计与实际应用相匹配的数据结构。 ??? 数据结构与算法设计的一般流程如下: ??? (1)数据结构与算法有全局和局部之分,当然先设计全局的,后设计局部的(通常在模块设计时进行)。 ??? (2)根据问题的特征,先查找已经存在的数据结构与算法,挑选最合适的(并不一定是最先进的)。如果不存在现成的,那么自己设计。 ??? (3)设计并且编写代码之后,要进行测试。如果不满足性能要求,那么要进一步优化数据结构和算法。?? (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |