课件
软件的复杂性
随着软件技术和应用的不断发展,软件系统的规模越来越大,复杂度也越来越高,在这种情况下,代码级别的软件复用已经远远不能满足大型软件开发的要求。
面对日益复杂的软件系统的设计与构造,软件工程师需要考虑的关键问题是,对整个系统的结构和行为进行抽象,一方面是寻求更好的方法,使系统的整体设计更容易理解,另一方面是寻求构造大型复杂软件系统的有效方法,实现系统级的复用。
举例1
要求编写一个程序,该程序读入一个文本文件,统计在该文本文件中每个英文 单词出现的频率,并输出单词频率最高的100个单词。在编写这个程序的时候,重点会考虑哪些部分的设计呢?对于这个程序的设计,主要考虑选择合适的分词方法和查询算法,建立可以实现快速查找的数据结构,还会涉及到外部存储文件或数据库的构造,在代码构造时可以调用已有的 Python 代码库,也就是说,编写小规模的程序主要关注的是算法的选择、数据结构的设计和数据库的构造。
举例2
如果是开发一个 Web 信息检索系统,这时,应该关注哪方面呢?该系统要对发布在Web信息资源进行搜集、整理和组织,形成一个信息资源索引库,并通过检索界面将最符合用户要求的网站或网页提供给用户。这个系统比前面的词频统计程序要复杂得多,无法简单地用数据结构和算法来进行描述和设计。现在对整个系统的结构和行为进行抽象,一般网信息检索的过程为,系统先要从网上抓取网页,对网页信息进行处理,建立索引数据库,用户进行查询时根据输入的查询关键字在索引数据库中进行搜索,并对搜索结果进行处理和排序,最后返回一系列与用户查询相关的网页信息。这样整个系统就可以抽象成如下三个部分:
对应上面的三个部分/过程,整个系统可以划分成三个功能模块:
- 信息采集模块:实现网页搜集功能
- 标引处理模块:实现预处理功能
- 信息检索模块:实现检索服务的功能
除了模块分解之外,还要考虑使用什么策略来实现非功能需求的目标,比如可以采用分布式的文件系统和计算框架,提高大规模网页搜集和检索的效率等等。
从这事例可看出,对于大规模的复杂系统来说,对系统的全局结构设计和规划,变得比算法的选择和数据结构的设计明显要重要得多。
处理复杂性
在工程领域,体系结构设计被广泛地应用于处理复杂系统的设计问题。
比如说大型的客机在整体上被划分成机翼、机身、尾翼、起落装置和动力装置等不同的组成部分,其总体结构也要根据技术的要求和使用环境,来确定飞机的外形、总体布局、发动机选型等。机体的设计还要满足强度、刚度、疲劳、损伤容限等一些安全性的要求。
起源于建筑学的“体系结构”
体系结构这个词起源于建筑学,它是从系统的宏观层面上描绘出整个建筑的结构,把一个复杂的建筑体拆分成一些基本的建筑模块,并通过这些基本的模块进行有机地组合,形成整个建筑。
建筑的体系结构设计要满足坚固、适用、赏心悦目的要求。具体包括以下方面:
- 有哪些基本的建筑单元?比如砖、瓦、梁、柱、屋顶、外墙、门窗等
- 如何将这些基本单元进行组合形成整体建筑?
- 建筑单元怎样搭配才合理?
- 不同类型的建筑有什么典型的结构?比如欧洲古典风格和中国园林风格就是两种不同的建筑类型
- 如何快速节省地进行建造施工?
- 怎样对建造完成的建筑进行适当的修改?
- 如何保证单元的更改不会影响整栋建筑的质量?
软件体系结构概念
软件体系结构(Software Architecture)包括构成系统的设计元素的描述、设计元素之间的交互、设计元素的组合模式以及在这些模式中的约束。
软件体系结构主要包含 5 个方面的内容:
- 构件:代表着一组基本的构成要素
- 连接件:构成要素之间的连接关系
- 约束:作用于这些要素或连接关系上的限制条件
- 质量:系统的质量属性,如性能、可扩展性、可修改性、可重用性、安全性等
- 物理分布:要素连接之后形成的拓扑结构,描述了软件到硬件的映射
简单地说,软件体系结构 = 构件 + 连接件 + 约束,它提供了在更宏观的结构层次上来理解系统层面问题的一个骨架,它主要关注于把一个复杂系统从整体到部分的一个最高层次的划分、对于设计模块的一个功能定义,以及如何把这些模块组合成为一个完整的系统。系统的分解要满足设计目标的要求,反映开发中具有重要影响的设计决策,从而保证系统的质量要求。
构件
在软件体系结构的概念中,构件是具有某种功能的可复用的软件结构单元,它们表示系统中主要的计算元素和数据存储。
任何在系统运行中承担一定功能或者发挥一定作用的软件体,都可以看作是构件,像函数、模块、对象、类、文件、相关功能的集合等。
构件作为一个封装的实体,只能通过它的接口和外部环境进行交互,其内部的结构是被隐藏起来的。
构件的功能以服务的形式体现出来,并通过接口向外发布,进而产生与其他构件之间的关联。
连接
连接是构件之间建立和维护行为关联和信息传递的一个途径。它需要两个方面的支持:一个是连接发生和维持的机制,另一个是连接的协议。
一般来说,基本的连接机制包括:过程调用、中断、I/O、事件、进程、线程、共享、同步、 并发、消息、远程调用、动态连接、API 等等
协议是连接的规约,对于过程调用来说可以是参数的个数和类型、参数排列次序等。对于消息传送来说可以是消息的格式。除了连接实现的难易程度之外,同步或者异步,是影响连接实现的复杂因素之一。
连接件
连接件表示构件之间的交互,并实现构件之间的连接。
比如说,管道、过程调用、事件广播、客户机-服务器、数据库连接等,都是属于连接件。连接件也可以看作是一类特殊的构件,它和一般的构件的区别在于,一般构件是软件功能设计和实现的承载体,而连接件是负责完成构件之间信息交换和行为联系的专用构件。
软件体系结构的目标
初期的总体设计,是决定软件产品成败的一个关键因素。往往错误的设计决策会造成灾难性的后果。
- 在软件设计过程中,可以对一些经过实现证明的体系结构进行复用,从而提高设计的效率和可靠性,降低设计复杂度。另外,也可以把一些公共部分抽象提取出来,形成公共类和工具类,为大规模开发提供基础和规范。
- 体系结构的设计要具备灵活性,在产品开发的演化过程中,可以很方便地增加新的功能,更好的适应用户需求的变化。
- 由于体系结构构件了一个相对小的简单的模型,这样就把复杂的问题简单化,使系统更加易于理解和实现。
- 软件体系结构突出体现了早期的设计决策,展现出系统满足需求的能力。
软件体系结构的发展
软件系统规模在迅速增大的同时,软件开发方法也经历了一系列变化。软件体系结构也从最初的一个模糊概念,发展成一个日趋成熟的技术。
从 20 世纪 70 年代开始,出现了面向过程的开发方法,系统被划分成不同的子程序,子程序之间的调用关系就构成了系统的结构,软件结构成为开发的一个明确概念。
到了 80 年代,面向对象方法逐渐兴起和成熟,系统被划分成不同的对象,并采用统一建模语言来描述系统的结构。
90 年代开始,软件开发强调构件化技术和体系结构技术,体系结构也成为软件工程领域的一个研究热点,出现了体系结构风格、框架和设计模式这样一些概念。
2000 年之后,面向服务的体系结构成为面向对象模型的替代模型,它具备分布式、跨平台、互操作和松散耦合等特点,致力于解决企业信息化过程中不断变化的需求,和异构环境集成的难题。
在这个发展过程中,软件系统的基本模块它的粒度越来越大,系统的结构越来越趋向分布和开放,所解决的问题也从技术本身转向商务过程。
下面介绍体系结构风格、设计模式和框架的概念,及它们的区别。
风格、模式和框架
体系结构风格用于描述某一个特定应用领域中系统组织的惯用模式,反映了领域中众多系统所共有的结构和语义特性。比如说 MVC 就是一种常见的体系结构风格。
设计模式描述了软件系统设计过程中常见问题的一些解决方案,一般是从大量的成功实践中总结出来的,而且被广泛公认的一些实践和知识。观察者模式是一种常用的设计模式,主要用于解决事件处理的问题。
软件框架是由开发人员定制的应用系统的骨架,是整个或者部分系统的可重用的设计,一般由一组抽象的构件和构件实例之间的交互方式组成。像 Django 就是一个开放源代码的外部应用框架,是由 Python 写成的,包括面向对象的映射器,基于正则表达式的 URL 分发器、视图系统和模板系统这样一些核心的构件。
框架和体系结构的关系:
- 体系结构是一种设计规约,而框架是一种具体实现,只不过它实现的是应用领域的共性部分,是领域中最终应用的模板;
- 体系结构的目的是指导软件系统的开发,而框架的目的是设计的复用,确定了框架之后,软件体系结构也随之确定;
- 对于同一种软件体系结构,比如说 Web 开发中的 MVC,可以通过多种框架来实现,像前端有 ANGULAR、BACKBONE,后端有 python 的 django 等框架
框架和设计模式的关系:
- 框架给出的是整个应用的体系结构,而设计模式给出的是单一设计问题的解决方案;
- 比如说一个网络游戏,可以基于网易的 Pomelo 框架开发,这是一个基于 Node.js 的高性能分布式游戏服务器框架,在实现某个动画功能时,可能会使用观察者设计模式,来实现自动化的通知更新;
- 设计模式的目的是改善代码结构,提高程序的结构质量,框架强调的是设计的重用性和系统的可扩展性,目的是缩短开发周期,提高开发质量;