第3章 软件系统设计.docx
《第3章 软件系统设计.docx》由会员分享,可在线阅读,更多相关《第3章 软件系统设计.docx(50页珍藏版)》请在冰豆网上搜索。
第3章软件系统设计
第3章软件系统设计
系统设计是把用户需求转化为软件系统的最重要的技术开发环节。
通常,系统设计的技术难度要比编程、测试的高。
所以程序员、测试员称为“员”,而设计师尊称为“师”。
在企业里,设计师的地位和收入通常高于程序员和测试员。
据说WindowsNT的一位系统设计师拥有8辆法拉利跑车,让Microsoft公司的一些程序员十分眼红。
但你只能羡慕而不能愤恨,因为并不是每个程序员都有本事成为复杂软件系统的设计师。
关于软件系统设计的方法论很多,开发人员既要学习新东西,又要避免被大量的新术语搞昏了头脑。
本章论述了软件系统设计的5个核心内容:
体系结构设计、用户界面设计、数据库设计、模块设计、数据结构和算法设计。
旨在帮助开发人员搞清楚“设计什么”以及“如何设计”。
系统设计的好坏在根本上决定了软件系统的优劣。
我们可以断言“差的系统设计必定产生差的软件系统”,但是不能保证“好的系统设计必定产生好的软件系统”。
因为在设计之前有需求开发工作,在设计之后还有编程、测试和维护工作,无论哪个环节出了差错,都会把好事搞砸了。
据说上帝把所有的女士都设计成天使,可是天使们在下凡的时候,有些人双脚先着地,有些人脸先着地。
上帝的这一疏忽让很多女士伤透了心。
所以我们在开发软件时,一定要吸取这个教训。
3.1软件系统设计的核心内容
系统设计之源是软件需求,包括“功能性需求”与“非功能性需求”。
系统设计的目标就是使所设计的系统能够被开发方顺利地实现,并且恰如其分地满足用户的需求,使开发方和用户的利益极大化。
开发人员不万不能偏离需求,为了追求技术的先进性而开展系统设计工作。
人们自然而然地采用“分而治之”的方法进行系统设计。
分而治之是指把一个复杂的问题分解成为若干个简单的问题,然后逐个解决。
这种朴素的思想来源于人们生活与工作经验,完全适合于技术领域。
依据“分而治之”的思想,我们把系统设计过程划分为两个阶段:
高层设计阶段和详细设计阶段。
高层设计阶段的重点是体系结构设计。
详细设计阶段的重点是用户界面设计、数据库设计、模块设计、数据结构与算法设计等。
如图3-1所示。
高层设计阶段
实现与测试
详细设计阶段
模块设计
数据库设计
数据结构与算法设计
用户界面设计
体系结构设计
需求开发
图3-1系统设计过程示意图
一般地,现代软件系统设计的核心内容是:
体系结构设计、用户界面设计、数据库设计、模块设计、数据结构与算法设计。
系统设计师应当全面掌握上述核心内容的设计方法和规则。
为了加深印象,我们作个比喻。
如果把软件系统比为人体,那么体系结构、用户界面、数据库、模块、数据结构与算法都能在人身上找到有趣的对应。
一、体系结构
体系结构如同人的骨架。
如果某个家伙的骨架是猴子,那么无论怎样喂养和美容,这家伙始终都是猴子,不会成为人。
人的身材大小取决于骨架大小,天生小个子的人基本上不可能成为威猛的大汉,后天再努力(例如锻炼和吃喝)也白搭。
由此可见,体系结构乃是系统设计的重中之重。
二、用户界面
用户界面如同人的外表,最容易让人一见钟情或一见恶心。
象人类追求心灵美和外表美那样,软件系统也追求(内在的)功能强大和(外表的)界面友好。
现代社会的生活节奏越来越快,人们已少有兴趣去品味深藏不露的内在美。
如果把Unix系统比作是健壮的汉子和妇人,那么Windows系统就象妩媚的小白脸和狐狸精。
想不到Windows系统竟然能兴风作浪,占去操作系统的大半市场。
有鉴于此,我们在设计软件时不要沉迷于技术,而要多多思考什么样的界面才能让用户更加喜欢。
三、数据库
顾名思义,数据库是存储和处理数据用的。
人体的数据库是大脑,知识相当于数据,全存在大脑里。
如果脑子里存储的知识很多,那么这个人就显得博学。
如果脑子处理知识的速度很高,那么这个人就显得聪明。
很多人误以为数据库设计就是设计一些表格,觉得那是轻而易举的事情。
唉,傻瓜的脑袋并不比正常人的小,他之所以傻是因为脑子里面存储的东西太少了,并且放进去、取出来的速度太慢了。
数据库设计的主要挑战是“高速处理大容量的数据”。
四、模块
模块如同人的器官。
每个器官都具有特定的功能,器官们依附在骨架上。
模块是软件系统的部件,它们安插在体系结构上(否则运行起来掉光光了)。
人体中设计得最出色的模块是手,手只有几个基本动作(高度抽象),却能做无限多的事情。
而最糟糕的设计莫过于嘴巴,嘴巴将很有价值但毫无相干的几种功能如吃饭、说话、亲吻混为一体,使之无法并行处理,真乃人类之不幸。
所以我们在设计模块时要重视功能独立性,模块的接口应当充分体现该模块的行为特征(即抽象)。
人的嘴巴和耳朵虽然是相对独立的器官,但是如果一个人从小耳朵就聋了,他的嘴巴就只能发出“啊”“呜”的声音,等于丧失了说话的功能。
更奇怪的是,瞎子的听力却比正常人的更好。
那些看似独立的器官功能常有纠缠不清的时候,真是十分神奇并且十分可笑。
所以我们在设计模块时还要追求“高内聚、低耦合”。
五、数据结构与算法
数据结构与算法如同人的神经和肌肉,它分布在全身,让器官具有生命并能发挥功能。
人之所以能够全身运动,那是无数的神经和肌肉在起作用。
如果局部的神经和肌肉失效了,那么会导致对应的器官残废。
如果全局的神经和肌肉失效了,那么人就瘫痪了。
同理,数据结构与算法也有全局和局部之分,都要慎重设计。
传说女娲造的人分两种,女娲亲手捏出来的泥人成为了社会精英人物,而女娲用藤条沾着泥浆甩出来的东东则成了社会下层人物。
我们应该把软件当成自己的宝贝,用心地捏好,而不要随心所欲地乱捏。
3.2漫谈设计模式
20世纪90年代,面向对象(Object-Oriented)方法与技术在国内软件业界十分火爆,人们热衷于谈论“对象”并引以为荣。
十多年来,人们发表、出版了无数的文章和书籍。
现在,该写的似乎都写完了,没有新花样玩了,真是一片无聊。
设计模式(DesignPattern)及时问世,面向对象爱好者们终于有了新的追求。
1995年,ErichGamma,RichardHelm,RalphJohnson,JohnVlissides(戏称“四人帮”)出版了《DesignPatterns:
ElementsofReusableObject-OrientedSoftware》,该书的中译本已于2000年出版[Gamma2002]。
“四人帮”这本书的主要贡献是:
确立了设计模式这个术语,创导了一种新的面向对象设计思潮。
该书出版后,全世界参与设计模式研究的人数呈爆炸性地增长。
该书的负面效应是:
这本书深奥无比,读者被分成两类,即“看得懂设计模式的”和“看不懂设计模式的”,后者居多。
很多人刚入门时就被吓住了,知难而退。
何为“模式”和“设计模式”?
并没有确切的定义,但是人们的脑子里面都有模式的概念。
让我们看看一些设计模式研究者的观点。
模式描述了在我们周围不断重复发生的问题,以及该问题的解决方案的核心,这样你就能一次又一次地使用该解决方案而不必重复劳动。
[Gamma2002,P2]
——建筑设计大师ChristopherAlixander,1977
内行的设计者知道,解决任何问题并不一定都要从零开始做起,他们更愿意复用以前使用过的解决方案。
当找到一个好的解决方案时,他们会一遍又一遍地使用。
你会在许多面向对象系统中看到可复用模式。
这些模式能解决对应的设计问题,使面向对象设计更加灵活和优雅。
熟悉这些模式的人们不必重新发明它们,能够立即将它们应用于设计之中。
一旦懂得了设计模式,许多设计方案自然而然就产生了。
[Gamma2002,P1]
——“四人帮”,1995
人们在自己的环境中不断发现问题和寻找问题的解决方案时,发现有一些问题及其解决方案不断变换面孔后重复出现,在这些不同的面孔后面有着共同的本质,这些共同的本质就是模式。
[阎宏2002,P3]
——《Java与模式》的作者阎宏,2002
台湾作家蔡学庸先生对“设计模式好还是不好”作了通俗而精辟的解释:
基本上,模式就是一种公式化的表现,究竟公式化是不是好事?
以艺术来说,公式化的结果会造成僵化,所以负面效果居多。
电影号称“第八艺术”,拍电影是一种艺术创作,所以电影里最好不要出现太多的公式,否则肯定被影评人痛批为“毫无新意”。
对工程而言,公式化是好事。
公式都是千锤百炼的的成果,运用这些公式可以确保工程具备一定的质量,并且能加快工程的进展。
软件开发也是一项工程,所以需要尽量地运用公式。
尽管软件技术发展非常快,但是仍然有非常多的设计模式可以让我们套用。
关于体系结构设计的经典名著是MaryShaw和DavidGarlan所著的《SoftwareArchitecture:
PerspectiveonAnEmergingDiscipline》[Shaw96]。
该书论述了常见的体系结构模式:
✧PipesandFilters(管道与过滤器)
✧DataAbstractionandObject-OrientedOrgnization(数据抽象与面向对象组织)
✧Event-Based/ImplicitInvocation(消息驱动/隐式调用)
✧LayeredSystems(层次结构系统)
✧Repositories(仓库)
✧Interpreters(解释器)
✧ProcessControl(过程控制)
✧DistributedSystems(分布式系统)
✧Client/Server(客户机/服务器)
✧Main/SubPrograms(主程序/子程序)
✧StateTransition(状态转换)
✧DomainSpecificStyles(领域专用模式)
软件的用户界面也有模式。
Microsoft推出每一代Windows操作系统的时候,已经不知不觉地设计了应用软件的用户界面模式。
所以Windows应用软件的模样看上去都差不多。
应用软件的用户界面由许多界面元素构建而成,常见的界面元素(模式)有:
✧主窗口/子窗口/对话框
✧下拉菜单/弹出菜单
✧工具条/图标按钮
✧基本控件如命令按钮、输入框、选择框、列表框等等
我们在大学学习了《数据结构》这门课程,经典的数据结构其实就是程序中数据组织形式的模式。
几乎所有的软件都会直接或间接地使用那些经典数据结构,例如:
链表、栈、队列、树(二叉树)、图等等。
确切地说,“四人帮”的《DesignPattern》所论述的是接口设计模式而非其它设计模式。
接口设计模式比体系结构设计模式的粒度要小得多,更加讲究设计的细节。
只有懂得面向对象程序设计方法、能够熟练使用C++或者Java的人,才可能掌握接口设计模式。
难怪很多读者看不懂“四人帮”的《DesignPattern》,误以为所有的设计模式都是那么难学。
“四人帮”总结的接口设计模式有:
✧构造型模式
ØAbstractFactory(抽象工厂)
ØBuilder(建造器)
ØFactoryMethod(工厂方法)
ØPrototype(原型)
ØSingleton(单例)
✧结构性模式
ØAdapter(适配器)
ØBridge(桥梁)
ØComposite(合成)
ØDecorator(装饰)
ØFaçade(外观)
ØFlyweight(享元)
ØProxy(代理)
✧行为型模式
ØChainofResponsibility(责任链)
ØCommand(命令)
ØInterpreter(解释器)
ØIterator(迭代器)
ØMediator(协调器)
ØMemento(备忘录)
ØObserver(观察者)
ØState(状态)
ØStrategy(策略)
ØTemplateMethod(模板方法)
ØVisitor(访问者)
阎宏所著的《Java与模式》厚达千页,他用中国道家哲学思想来阐述接口设计模式,该书的广度与深度比“四人帮”的有过之而无不及。
可怜的读者又被分成两类:
“懂Java设计模式的”和“不懂Java设计模式的”
小结:
设计模式的应用价值在于它能帮助人们简便地复用以前成功的设计方案。
设计模式不是凭空产生的,只有对应用域问题及其解决方案进行抽象和分析,发现本质,并按照一定的格式记录下来,才能成为可以被人们复用的设计模式。
3.3体系结构设计
3.3.1体系结构设计原则
中国科学院的杨叔子院子如是言:
文学中有科学,音乐中有数学,漫画中有现代数学的拓扑学。
漫画家可以“几笔”就把一个人画出来,不管怎么美化或丑化,就是活像。
为什么?
因为那“几笔”不是别的,而是拓扑学中的特征不变量,这是事物最本质的东西。
体系结构是指软件系统的基本和主体的形态,也就是软件系统中“最本质”的东西。
一个软件系统的体系结构设计得好不好,可以用“合适性、结构稳定性、可扩展性、可复用性”这些特征量来评估。
我们对这些特征量进行分析、论述,可以归纳出用于指导体系结构设计的一些原则。
3.3.1.1合适性
人们为什么要开发软件系统?
是为了满足客户的需求,从而使开发方和客户方共同获益。
所以系统设计之源是需求,这是由商业目标决定的。
高水平的设计师高就高在“设计出恰好满足客户需求的软件,并且使开发方和客户方获取最大的利益,而不是不惜代价设计出最先进的软件。
评估体系结构好不好的第一个指标就是“合适性”,即体系结构是否适合于软件的“功能性需求”和“非功能性需求”。
人们一般不会在需求文档中指定软件的体系结构,需求与体系结构之间并没有一一对应的关系,甚至没有明显的对应关系。
所以设计师可以充分发挥主观能动性,根据需求的特征,通过推理和归纳的方法设计出合适的体系结构。
经验不丰富的设计师往往把注意力集中在“功能性需求”而疏忽了“非功能性需求”,殊不知后者恰恰是最能体现设计水平的地方。
比方说设计住宅。
住宅的最基本的功能性需求是“吃喝拉撒睡”,全世界人民“吃喝拉撒睡”的方式都是差不多的。
住宅的非功能性需求主要是让人住得舒服,可谓丰富多彩。
住宅的种类非常多,如茅草屋、窑洞、筒子楼、酒店、别墅等等。
窑洞的体系结构与别墅的有天壤之别,你能说后者一定比前者好吗?
不能,因为没有可比度。
如果一名建筑师受政府委托给广大的中国陕北农民设计住宅,他应当设计更好的窑洞而非别墅。
理由很简单,因为广大的陕北农民住不起别墅,而那里的土地特别适合于建窑洞。
窑洞对于当地的农民而言是非常实用而且成本低廉的住宅,人们已经住了几百年了,在中国实现全民小康之前,窑洞不会消逝。
窑洞最大的危险是在下大雨和下大雪的时候容易坍塌,如果建筑师能够设计出“安全、舒适、便宜”的窑洞,那么他真是功德无量。
对于软件系统而言,能够满足需求的设计方案可能有很多种,究竟该选哪一种?
此时商业目标是决策依据,即选择能够为开发方和客户方带来最大利益的那个设计方案。
大部分软件开发人员天生有使用新技术的倾向,而这种倾向对开发商业产品而言可能是不利的,切记切记。
3.3.1.2结构稳定性
体系结构是系统设计的第一要素,详细设计阶段的工作如用户界面设计、数据库设计、模块设计、数据结构与算法设计等等,都是在体系结构确定之后开展的,而编程和测试则是更后面的工作。
如果体系结构经常变动,那么建筑在体系结构之上的用户界面、数据库、模块、数据结构等等也跟着经常变动,用“树倒猢狲散”来比喻很恰当,这将导致项目发生混乱。
自然科学告诉我们,宇宙间万物无时无刻不在运动。
由于地球上的生活环境保持相对稳定,以致于我们压根就意识不到自己是活生生的导弹,人们可以无忧无虑地吃饭和睡觉,干些工作。
当前中国有几句流行的至理名言:
“稳定压倒一切”、“发展是硬道理”。
发展的前提条件是稳定,社会如此,开发软件产品也是如此。
所以体系结构一旦设计完成,应当在一定的时间内保持稳定不变,只有这样才能使后续工作顺利开展。
前面讲了,体系结构是依据需求而设计的。
如果需求变更了,很可能导致体系结构也发生变更,那么“保持结构稳定”岂非成了空想?
高水平的设计师应当能够分析需求文档,判断出哪些需求是稳定不变的,哪些需求是可能变动的。
于是根据那些稳定不变的需求设计体系结构,而根据那些可变的需求设计软件的“可扩展性”。
3.3.1.3可扩展性
可扩展性是指软件扩展新功能的容易程度。
可扩展性越好,表示软件适应“变化”的能力越强。
由于软件是“软”的,是否它天生就容易扩展新功能?
这要视软件的规模和复杂性而定。
如果软件规模很小,问题很简单,那么扩展功能的确比较容易。
要是软件的代码只有100行,这时就无所谓“可扩展性”了,你想怎么扩展都可以。
如果软件规模很大,问题很复杂,倘若软件的可扩展性不好,那么该软件就象用卡片造成的房子,抽出或者塞进去一张卡片都有可能使房子倒塌。
是否任何软件在设计的时候都要考虑可扩展性?
不见得。
如果确信某个软件在它淘汰之前永远都不会变更(如一次性产品),那么在设计阶段就没有必要考虑可扩展性,这样省事省力。
可扩展性越来越重要,这是由现代软件的商业模式决定的:
✧社会的商业越发达,需求变化就越快。
需求变化必将导致修改(或者扩展)软件的功能,现代软件的规模和复杂性要比十年前的大得多(对比一下操作系统的变化就明白了),如果软件的可扩展性比较差的话,那么修改(或者扩展)功能的代价会很高。
✧现代软件产品通常采用“增量开发模式”,开发商不断地推出软件产品的新版本,从而不断地获取增值利润。
如果软件的可扩展性比较差的话,每次开发新版本的代价就会很高。
虽然开发商抓住了商机,但却由于设计水平差而导致没有赚取多少利润,真是要活活气死。
体系结构的稳定性是根据那些稳定不变的需求而设计的,体系结构的可扩展性则是依据那些可变的需求而设计的。
从字面上看,稳定性和可扩展性似乎有点矛盾。
两者之间存在辨证的关系:
如果系统不可扩展的话,那么就没有发展前途,所以不能只关心稳定性而忽视可扩展性;而软件系统“可扩展”的前提条件是“保持结构稳定”,否则软件难以按计划开发出来,稳定性是使系统能够持续发展的基础。
所以稳定性和可扩展性都是体系结构设计的要素。
人们对于物质有喜新厌旧的天性,你可以经常改变住房的装璜和摆设,但不会在每次变动时都去折墙、拆柱、挖地基(否则就是搞破坏了)。
在软件开发过程中,变化是司空见惯的事情。
如果每次变化都导致体系结构发生大的变动,那简直就是“伤筋动骨”,这样的体系结构无疑是败笔之作。
下文将介绍“层次结构”这种重要的体系结构模式。
层次结构天生具有良好的可扩展性,而且在扩充或修改功能时,基本不会破坏原有结构的稳定性。
3.3.1.4可复用性
复用就是指“重复利用已经存在的东西”。
被复用的对象可以是有形的物体,也可以是无形的知识财富。
复用不是人类懒惰的表现而是智慧的表现。
因为人类总是在继承了前人的成果,不断加以利用、改进或创新后才会进步。
复用的有利于提高产品的质量、提高生产率和降低成本。
由经验可知,通常在一个新系统中,大部分的内容是成熟的,只有小部分内容是创新的。
一般地可以相信成熟的东西总是比较可靠的(即具有高质量),而大量成熟的工作可以通过复用来快速实现(即具有高生产率)。
勤劳并且聪明的人们应该把大部分的时间用在小比例的创新工作上,而把小部分的时间用在大比例的成熟工作中,这样才能把工作做得又快又好。
把复用的思想应用于软件开发,称为软件复用。
技术开发活动与管理活动中的任何成果都可以被复用,如思想方法、经验、程序、文档等等。
据统计,世上已有1000亿多行程序,无数功能被重写了成千上万次,真是浪费哪。
面向对象学者们的口头禅就是“请不要再发明相同的车轮子了”。
复用的意义很容易理解,人们也乐意复用以前的成果,但是前提条件是该成果具有比较好的可复用性。
可复用性是指成果被复用的容易程度。
国内大学里的软件成果的可复用性普遍极差。
每一次毕业设计时,毕业生们都会把上一届毕业生留下的软件臭骂一通,然后全部推翻重做。
他们毕业之后,下一届的人们会接着臭骂下去,这样一届接一届,始终不见学校拿出象样的软件来。
企业成功地开发了某个软件产品之后,如果下个新产品能够复用上个产品的体系结构的话,那么新产品的系统设计的成本和风险将大大降低。
可复用性是设计出来的,而不是偶然碰到的。
要使体系结构具有良好的可复用性,设计师应当分析应用域的共性问题,然后设计出一种通用的体系结构模式,这样的体系结构才可以被复用。
(请参见本章3.2节对设计模式的论述)
3.3.2体系结构设计的规程与模板
体系结构设计的一般规程如表3-1所示。
目的
分析与设计软件的体系结构。
通过系统分解,确定子系统的功能和子系统之间的关系,以及模块的功能和模块之间的关系,产生《体系结构设计报告》。
角色与职责
项目经理指定若干名开发人员从事体系结构设计。
启动准则
体系结构设计人员已经确定。
输入
《产品需求规格说明书》
主要步骤
第一步:
设计准备
第二步:
确定影响系统设计的约束因素
第三步:
确定设计策略
第四步:
系统分解与设计
第五步:
撰写体系结构设计文档
第六步:
设计评审
输出
《体系结构设计报告》
结束准则
《体系结构设计报告》已经完成,并且通过了技术评审。
度量
体系结构设计人员统计工作量以及文档的规模,汇报给项目经理。
表3-1体系结构设计的一般规程
体系结构设计的主要步骤如图3-2所示。
Step3.
确定
设计
策略
Step2.
确定
约束
因素
Step1.
设计
准备
Step4.
系统
分解
设计
Step6.
设计
评审
Step5.
撰写
文档
图3-2体系结构设计的主要步骤
第一步:
设计准备
项目经理分配系统设计任务,包括体系结构设计、模块设计、用户界面设计、数据库设计等。
如果系统设计的工作量比较大,人员比较多的话,可能产生一份阶段性的开发计划,如《系统设计计划》。
体系结构设计人员阅读需求文档,明确设计任务,并准备相关的设计工具(如RationalRose)和资料。
第二步:
确定影响系统设计的约束因素
体系结构设计人员从需求文档如《软件需求规格说明书》中提取需求约束,例如:
✧本系统应当遵循的标准或规范
✧软件、硬件环境(包括运行环境和开发环境)的约束
✧接口/协议的约束
✧用户界面的约束
✧软件质量的约束,如正确性、健壮性、可靠性、性能、易用性、清晰性、安全性、可扩展性、兼容性、可移植性等等。
有一些假设或依赖并没有在需求文档中明确指出,但可能会对系统设计产生影响,设计人员应当尽可能地在此处说明。
例如对用户教育程度、计算机技能的一些假设或依赖,对支撑本系统的软件硬件的假设或依赖等。
第三步:
确定设计策略
体系结构设计人员根据产品的需求,以及本产品的发展战略,确定设计策略(DesignStrategy)。
例如:
✧设计模式。
根据本产品的功能性需求和非功能性需求,确定体系结构设计模式。
✧扩展策略。
说明为了方便本系统在将来扩展功能,现在有什么措施。
✧复用策略。
说明本系统在当前“复用什么”以及将来“如何被复用”。
✧折衷策略。
说明当两个目标难以同时被优化时如何折衷,例如“时-空”效率折衷,复杂性与实用性之间的折衷。
第四步:
系统分解与设计
✧按照体系结构设计模式,将系统分解为若干子系统,确定每个子系统的功能以及子系统之间的关系。
绘制系统的总体结构图(包括物理图和逻辑图)。
✧将子系统分解为若干模块,确定每个模块的功能以及模块之间的关系,绘制子系统的结构图。
✧确定系统开发、测试、运行所需的软硬件环境。
第五步:
撰写体系结构设计文档
体系结构设计人员根据指定的模板撰写《体系结