主题
软件架构设计
架构基本概念(⭐⭐⭐)
软件架构 = 软件体系结构(学术界),处于需求分析和软件设计之间,填平了它们之间的鸿沟。
架构设计就是需求分配,即将满足需求的职责分配到组件上。
架构的本质
- 软件架构为软件系统提供一个结构、行为和属性的高级抽象。
- 软件架构风格是特定应用领域的惯用模式,架构定义一个词汇表和一组约束。
架构的作用
- 软件架构是项目干系人进行交流的手段。
- 软件架构是可传递和可复用的模型,通过研究软件架构可能预测软件的质量。
- 软件架构使推理和控制的更改更加简单,有助于循序渐进的原型设计,可以作为培训的基础。
- 能够支持项目计划和项目管理等活动。
提示
软件架构设计是降低成本、改进质量、按时和按需交付产品的关键因素。
架构设计与生命周期

4+1视图

- 逻辑视图:主要描述系统的功能性需求,即系统提供给最终用户的服务。它通过类图、包图等方式展现系统的功能。
- 开发视图:主要侧重于软件模块的组织和管理。通过目录结构和层次结构图来展示软件内部的需求,如软件开发的容易性、复用性和通用性,以及由于具体开发工具不同而带来的局限性。
- 进程视图:侧重于系统的运行特性,主要关注系统的并发行、分布性、系统集成性和容错能力,以及从逻辑视图中的主要抽象如何适合进程结构等。
- 部署视图:主要考虑如何把软件映射到硬件上,包括解决系统拓扑结构、系统安装和通信等问题。
架构描述语言ADL(⭐)
ADL是一种形式化语言,它在底层语义模型的支持下,为软件系统的概念体系结构建模提供了具体语法和概念框架。
- C2SADL:基于组件和消息
- Wright:分布、并发类型
- ACME:架构互换语言
- UniCon:基于组件和连接
- Rapide:基于事件
三个基本要素:
- 构件:计算或数据存储单元。
- 连接件:用于构件之间交互建模的体系结构构造块及其支配这些交互的规则。
- 架构配置:描述体系结构的构件与连接件的连接图。
基于架构的软件设计方法(⭐⭐⭐⭐)
基于架构的软件设计(Architecture-Based Software Design,ABSD)方法是架构驱动,即由构成架构的业务【商业】、质量和功能需求的组合驱动。
三个基础:
- 功能的分解:使用已有的基于模块的内聚和耦合技术。
- 通过选择架构风格来实现质量和商业需求。
- 软件模板的使用。
ABSD相关概念:
- 设计元素:自顶向下,递归细化。最顶层系统被分为概念子系统和若干个模板;概念子系统又被分解为概念构件和附加软件模板。
- 视角与视图:描述软件架构。不同的视角会有不同的视图。
- 用例与质量场景:用例用来捕获功能需求;质量场景(刺激、环境、响应)用来捕获质量需求。

提示
架构复审【架构评估】的目的是标识潜在的风险,及早发现架构设计中的缺陷和错误。
架构需求与设计过程

架构文档化
主要输出2个文档:
- 架构规格说明书
- 测试架构需求的质量设计文档
文档的完整性和质量是软件架构成功的关键因素。
文档的注意事项:
- 文档需要从使用者的角度进行编写
- 必须分发给所有与系统有关的开发人员
- 必须保证开发者手上的文档是最新的,但更新不能太频繁
架构实现与演化过程

软件架构风格(⭐⭐⭐⭐⭐)
架构风格定义了用于描述系统的术语表和一组指导构建系统的规则。
数据流风格
批处理
构件为一系列固定顺序的计算单元,构件之间只通过数据传递交互。每个处理步骤是一个单独的程序,每一步必须在前一步结束后开始,并且数据必须是完整的,以整体方式传递。

特点:大量整体数据、无需用户交互
| 优点 | 缺点 | 典型应用 |
|---|---|---|
|
|
|
管道-过滤器
一个处理步骤的输出是另一个处理步骤的输入,每个处理步骤由一个过滤器实现,其之间的数据由管道负责。构件是过滤器,连接件是管道。

特点:流式数据,弱用户交互,需要数据格式转换。
调用/返回风格
将复杂系统分解为若干个子系统,分而治之,降低复杂度,并且增强可修改性。

主程序/子程序
把问题分为若干个处理步骤。构件为主程序和子程序,连接件为过程调用,充当交互机制。调用关系具有层次性,其语义逻辑表现为主程序的正确性取决于它调用的子程序的正确性。
面向对象
构件是对象,对象是抽象数据类型的实例。数据的表示和它们的相应操作封装在一个抽象数据类型或对象上。
分层架构
构件组织成一个层次结构,连接件通过决定层间如何交互的协议来定义。每层为上层提供服务,使用下层的服务,只能见到与自己相邻的层。通过层次结构,可以将大的问题分解为若干个渐进的小问题逐步解决,可以隐藏问题的复杂度。修改某一层,最多影响其相邻的层(通常只影响上层)。

特点:
- 各个层次的组件形成不同功能级别的虚拟机。
- 多层相互工作,而且实现透明。
优点:
- 良好的可重用性,只要接口不变可用在其它位置。
- 可维护性好。
- 可扩展性好,支持递增设计。
缺点:
- 并不是每个系统都方便分层。
- 很难找到一个合适的、正确的层次抽象方法:层次多了会影响性能,层次少了可能带来逻辑结构划分不清楚的问题。
- 不同层次之间耦合度高的系统很难实现。
以数据为中心的风格
特点:数据共享
例子:操作系统的注册表
仓库体系结构
仓库是存储和维护数据的中心场所,即以数据为中心。
两种构件:
- 中央数据结构:说明当前数据的状态
- 对中央数据结构进行操作的独立构件
特点: - 数据存储在中心仓库,处理流程独立,支持交互。
- 数据与处理解耦合,可动态添加和删除处理组件;但这也导致需要加载数据,性能降低。
- 数据处理组件之间通常无依赖关系,支持并发调用。
例子:现代编译器的集成开发环境(包括代码编辑、语法高亮、代码编译、运行调试等),中心数据就是程序语法树。
黑板体系结构

包括知识源、黑板和控制三部分。知识源包括若干独立不同的计算单元,提供解决问题的知识。知识源响应黑板的变化,也只修改黑板。黑板是一个全局数据库,包含问题域解空间的全部状态,是知识源相互作用的唯一媒介。
本身黑板系统可以用数据库系统实现,只是在数据库系统的基础上加了触发机制:黑板上的信息变动时会触发知识源做相应的处理。
适用于解决复杂的非结构化问题,能在求解过程中综合运用多种不同知识源,使得问题的表达、组织和求解变得比较容易。
如何理解黑板体系结构?
比如一个医疗诊断系统:黑板存储病人的症状、体征和检验结果。不同的知识源(如心脏病专家模块、内分泌专家模块)会根据当前信息提出可能的诊断假设,最终系统综合所有假设得出最可能的诊断。
优点:
- 可更改性和可维护性
- 可重用的知识源
- 容错性和健壮性
缺点:
- 测试困难
- 不能保证有好的解决方案
- 难以建议好的控制策略
- 低效、开发困难
- 缺少并行机制
特点:在以数据为中心的基础上,使用中心数据触发业务逻辑部件。
典型示例:语音识别、模式识别、图像处理、知识推理。
超文本系统
构件以网状链接方式相互连接,用户可以在构件之间进行按照人类的联想思维方式任意跳转到相关构件。
通常应用在互联网领域。
现代集成编译环境一般采用此架构风格。
虚拟机风格
人为构建一个运行环境,解析与运行自定义语言,提高架构的灵活性。
优点:可灵活应对自定义场景
缺点:复杂度较高
解释器风格

组成部分:
- 完成解释工作的解释器引擎
- 包含将被解释的代码存储区
- 记录解释器引擎当前工作状态的数据结构
- 记录源代码被解释执行的进度的数据结构
具有解释器风格的软件中含有一个虚拟机,可以仿真硬件的执行过程和一些关键应用。解释器通常用来建立一种虚拟机以弥合程序语义与硬件语义之间的差异。缺点是执行效率较低。
适用于需要自定义规则的场景。
规则系统风格
以规则为中心,在解释器的基础上增加了经验规则(知识库),包括:
- 规则集
- 规则解释器
- 规则/数据选择器
- 工作内存
适用于人工智能领域、专家系统、DSS等。

独立构件风格
强调系统中的每个构件都是相对独立的个体,它们之间不直接通信以降低耦合度,提升灵活性。

特点:
- 系统由若干个子系统构成且成为一个整体
- 系统有统一的目标
- 子系统有主从之分
- 每一个子系统有自己的事情收集和处理机制
优点:
- 松耦合
- 良好的可重用性、可扩展性、可修改性
缺点:
- 构件放弃了对系统计算的控制。一个构件触发一个事件时,不能确定其他构件是否会响应它。而且即使它知道事件注册了哪些构件的过程,它也不能保证这些过程被调用的顺序。
- 数据交换的问题。
- 既然过程的语义依赖于被触发事件的上下文约束,关于正确性的推理就存在问题。
进程通信风格
构件是独立的进程,连接件是消息传递。构件通常是命名过程,消息传递的方式可以是点对点、异步或同步方式,以及远程过程调用等。
事件驱动风格
又称隐式调用风格。构件不直接调用一个过程,而是触发或广播一个或多个事件。构件中的过程在一个或多个事件中注册,当某个事件被触发时,系统自动调用在这个事件中注册的所有过程。一个事件的触发就导致了另一个模块中的过程调用。简单理解就是发布-订阅模式。

优点:为软件复用提供了强大的支持,为构件的维护和演化带来了方便。
缺点:放弃了对系统计算的控制。
例子:
- 编程环境中用于集成各种工具
- 数据库管理系统中确保数据的一致性约束
- 在用户界面系统中管理数据
- 编辑器中支持语法检查,监控断点事件等
相关技术:消息中间件的发布订阅功能,消息中间件是构件组装的常用手段。
汇总表:
| 体系结构风格 | 构件 | 连接件 |
|---|---|---|
| 批处理 | 独立的应用程序(计算单元) | 某种类型的媒介 |
| 管道-过滤器 | 过滤器 | 管道 |
| 主程序/子程序 | 主程序和子程序 | 过程调用 |
| 面向对象 | 对象(抽象数据类型的实例) | 过程调用 |
| 层次型 | 各层 | 由通过决定层间如何交互的协议来定义 |
| 仓库体系结构 | 中央数据结构及其操作 | 仓库与构件间的交互 |
| 进程通信风格 | 独立的进程 | 消息传递 |
| 事件系统风格 | 模块(过程或事件集合) | 以过程之间的隐式调用来实现 |
闭环控制架构【过程控制】
适用于嵌入式系统,用于解决简单闭环控制问题。
经典应用:空调温控,定速巡航

C2架构
了解即可,不必深究!

基本规则:
- 构件和连接件都有一个顶部和一个底部
- 构件的顶部要连接到连接件的底部,构件的底部要连接到连接件的顶部,构件之间不允许直连。
- 一个连接件可以和任意数目的其它构件和连接件连接
- 当两个连接件进行直接连接时,必须由其中一个底部到另一个的顶部
MDA(⭐⭐)
Model Driven Architecture,模型驱动架构,是一种形式化方法。 MDA起源于分离系统规约和平台实现的思想。
- Model:客观事物的抽象表示。
- Architecture:构件系统的部件、连接件及其约束的规约。
- Model Driven:使用模型完成软件的分析、设计、构建、部署、维护等各开发活动。
核心模型

- 计算无关模型【CIM】:CIM对系统中使用的重要的领域抽象进行建模,也称为领域模型。
- 平台独立模型【PIM】:具有高抽象层次、独立于任何实现技术的模型。如UML。
- 平台相关模型【PSM】:为某种特定实现技术量身定做,让你用这种技术中可用的实现构造来描述系统的模型。PIM会被变换成一个或多个PSM。
- 代码【Code】:用源代码对系统的描述(规约)。每个PSM都将被变换成代码。
主要目标
- 可移植性(Portability):先建立PIM,然后建立PSM,1个PIM可转换成多个PSM,要移植到另一个平台,只需将平台无关模型转成平台对应的相关模型即可。
- 互通性【互操作性】(Interoperability):整个开发过程都是模型驱动,标准化程度很高。
- 可重用性(Reusability)
- 文档和代码的一致性:代码是由模型生成的,所以具有天然的一致性。
软件架构复用(⭐⭐)
软件复用是一种系统化的软件开发过程,通过识别、分析、分类、获取和修改软件实体,以便在不同软件开发过程中重复使用它们。
软件开发过程中重复使用相同或相似软件元素的过程。软件元素包括:需求分析文档、设计过程、设计文档、程序代码、测试用例、领域知识等。
软件复用发展线路:

软件复用基本过程:

可复用资产范围有多广?
需求、架构设计、元素、建模与分析、测试、项目规划、过程、方法和工具、人员、样本系统、缺陷消除
特定领域软件架构(⭐⭐⭐)
DSSA(Domain Specific Software Architecture)以一个特定问题领域为对象,形成由领域参考模型、参考需求、参考架构等组成的开发基础架构,支持一个特定领域中多个应用的生成。
领域分类
- 垂直域:相同领域,深入
- 水平域:不同领域,平移
DSSA必备特征
- 一个严格定义的问题域和/或解决域。
- 具有普遍性,使其可以用于领域中特定应用的开发。
- 对整个领域的合适程度的抽象。
- 具备该领域固定的、典型的在开发过程中可重用的元素。
DSSA基本活动
- 领域分析:获得领域模型
- 领域设计:获得DSSA
- 领域实现:依据领域模型和DSSA开发和组织可重用信息
参与DSSA的人员

- 领域专家:有经验的用户、从事该领域中系统的需求分析、设计、实现以及项目管理的有经验的软件工程师等。领域专家的主要任务包括提供关于领域中系统的需求规约和实现的知识。
- 领域分析人员:应由具有知识工程背景的、有经验的系统分析员来担任。
- 领域设计人员:应由有经验的软件设计人员来担任。
- 领域实现人员:应由有经验的程序设计人员来担任。
DSSA建立过程
DSSA的建立过程是并发的、递归的、反复的、螺旋形的,其目的是将用户的需求映射为基于实现限制集合的软件需求,这些需求定义了DSSA。
- 定义领域范围
- 定义领域特定的元素
- 定义领域特定的设计和实现需求约束
- 定义领域模型和架构
- 产生、搜集可重用的产品单元
三层次模型

软件产品线(⭐⭐⭐)
软件产品线是指一组软件密集型系统,它们共享一个公共的、可管理的特性集,满足某个特定市场或任务的具体需要,是以规定的方式用公共的核心资产集成开发出来的。即围绕核心资产库进行管理、复用、集成新的系统。
核心资产库是产品构造的基础,领域工程的所有结果的集合。

特征:过程驱动,以架构为中心的核心产品,特定领域的技术支持
成功实施产品线的主要因素:
- 对该领域具备长期和深厚的经验
- 一个用于构建产品的好的核心资源库
- 好的产品线架构
- 好的管理支持(软件资源、人员组织、过程)
构件(⭐⭐⭐)
构件的定义
定义1:软件构件是一种组装单元,它具有规范的接口规约和显式的语境依赖。软件构件可以被独立地部署并由第三方任意地组装。
定义2:构件是某系统中有价值的、几乎独立的并可替换的一个部分,它在良好定义的体系结构语境内满足某清晰的功能。
定义3:构件是一个独立发布的功能部分,可以通过其接口访问它的服务。

构件系统架构特性:
- 构件系统体系结构由一组平台决策、一组构件框架和构件框架之间的互操作设计组成。
- 构件框架是一种专用的体系结构(通常围绕一些关键的机制),同时也是一组固定地作用域构件层次机制的策略。
- 概念框架的互操作设计包括系统体系结构连接的所有框架间的互操作的规则。
- 构件是一组通常需要同时部署的原子构件。构件和原子构件之间的区别在于:大多数原子构件永远都不会被单独部署(尽管它们可以被单独部署)。
- 一个原子构件是一个模块和一组资源。
- 模块是一组类和可能的非面向对象的结构体,比如过程或者函数。
- 资源是一个类型化的项的固定集合。资源这个概念可以包含代码资源,进而包含模块。问题在于除了编译器编译一个模块或包生成的资源外,还可能存在其它的资源。在”纯对象“的方法中,资源是外部化的不可改变的对象——不可改变是因为构件没有持久化的标志,而且复制不能被区分。
- 系统构件组装分为三个不同层次:定制、集成、扩展。
构件的复用
检索与提取构件
方法 特点 基于关键字的检索 树形或有向无回路图结构 刻面检索法 利用Facet描述构件执行的功能、被操作的数据、构件应用的语境或任意其它特征。如分多个刻面:应用领域、使用环境、功能 超文本检索法 按照人类的联想思维方式任意跳转到包含相关概念或构件的文档 理解与评价构件
- 要复用构件,准备地理解构件至关重要。特别是对构件修改使用时。
- 为达到目的,必须要求构件的开发过程遵循公共标准。
- 一般构件库的文档中全面而准备地说明以下内容:
- 构件的功能与行为
- 相关的领域知识
- 可适应性约束条件与例外情形
- 可以预见的修改部分及修改方法
修改构件
- 理想状态下是直接复用构件库中现成的构件,但大多数情况下,必须对构件进行或多或少的修改以应对新需求。
- 为了减少构件修改的工作量,要求开发人员尽量使构件的功能、行为和接口设计更为抽象化、通用化和参数化。这样,复用者即可通过对实参的选取来调整构件的功能或行为。如果这种调整仍然不足以使构件适用于新系统,复用者就必须借助设计信息和文档来修改构件。
- 构件库中若无修改使用的构件,则按新需求开发构件并存入构件库。
组装构件
组装的3种方式:
- 基于功能的组装:采用子程序调用和参数传递的方式将构件组装起来。
- 基于数据的组装:仍然是传统的子程序调用与参数传递,但它所依赖的软件设计方法不再是功能分解,而是面向数据的设计方法。例如:Jackson系统开发方法。
- 面向对象的组装:如果从类库中检索出来的基类能够完全满足新系统的需求,则可以直接应用。否则,必须以基类为父类,生成相应的子类以满足新系统的需求。
构件组装失配问题:
- 由构件引起的失配:包括由于系统对构件基础设施、构件控制模型和构件数据模型的假设存在冲突引起的失配。
- 由连接子引起的失配:包括由于系统对构件交互协议、连接子数据模型的假设存在冲突引起的失配。
- 由于系统成分对全局体系结构的假设存在冲突引起的失配等。
要解决失配问题,首先需要检测出失配问题,并在此基础上通过适当的手段消除。
构件分类
从构件的外部形态来看,构件可分为5类:
- 独立而成熟的构件:已在实际运行环境多次检验,该类构件隐藏了所有接口,用户只需要用规定好的命令进行使用。如:数据库管理系统、操作系统等。
- 有限制的构件:有限制的构件提供了接口,指出了使用的条件和前提,这种构件在装配时,会产生资源冲突、覆盖等影响,在使用时需要加以测试。例如,各种面向对象程序设计语言中的基础类库等。
- 适应性构件:适应性构件进行包装或使用了接口技术,把不兼容、资源冲突等进行了处理,可以直接使用。这种构件可以不加修改地使用在各种环境中。例如ActiveX等。
- 装配的构件:装配的构件在安装时,已经装配在操作系统、数据库管理系统或信息系统不同层次上,使用胶水代码就可以进行连接使用。目前一些软件商提供的大多数软件产品都属于这一类。
- 可修改的构件:对原构件修改错误、增加新功能,可以利用重新“包装”或写接口来实现构件的版本替换。这种构件在应用系统开发中使用得比较多。
中间件(⭐⭐⭐)
中间件是一类构件,是一类系统软件。
特点:简化结构、屏蔽差异、利于复用。

采用中间件技术的优点:
- 面向需求:设计师集中精力于业务逻辑本身。
- 业务的分隔和包容性:应用开发人员可以按照不同的业务进行功能的划分,体现为不同的接口或交互模式。
- 设计与实现隔离:构件对外发生作用或构件间的交互,都是通过接口进行的,构件使用者只需要知道构件的接口,而不必关系其内部实现,这是设计与实现分离的关键。
- 隔离复杂的系统资源:架构很重要的一个功能是将系统资源与应用构件隔离,这是保证构件可复用甚至“即插即用”的基础,与中间件的意图也是一致的。
- 符合标准的交互模型:中间件实现了架构的模型,实现了标准的协议。
- 软件复用:中间件提供了构件封装、交互规则、与环境的隔离等机制,这些都为软件复用提供了方便的解决方案。
- 提供对应用构件的管理:基于中间件的软件可以方便地进行管理,因为构件总可以通过标识机制进行划分。
中间件分类
| 分类 | 特点 | 示例 |
|---|---|---|
| 通信处理(消息)中间件 | 可靠、高效、实施跨平台通信。 | eLink、MQSeries |
| 事务处理(交易)中间件 | 事务分发、负载均衡 | Tuxedo |
| 数据存取管理中间件 | 为虚拟缓冲存取、格式转换、解压等带来方便 | |
| Web服务器中间件 | 有负载均衡、缓存、安全性等功能 | |
| 安全中间件 | 加密、认证 | |
| 跨平台和架构的中间件 | 解决跨平台问题 | CORBA |
| 专用平台中间件 | 为特定应用领域设计领域参考模式,建立相应架构 | |
| 网络中间件 | 功能包括网管、接入、网络测试、虚拟社区 和虚拟缓冲等。 |