软件架构之架构风格
9.3 软件架构风格
软件架构设计的一个核心问题是能否使用重复的软件架构模式,即能否达到架构级别的软件重用。也就是说,能否在不同的软件系统中,使用同一架构。基于这个目的,学者们开始研究和实践软件架构的风格和类型问题。
软件架构风格是描述某一特定应用领域中系统组织方式的惯用模式(idiomatic paradigm)。架构风格定义了一个系统家族,即一个架构定义一个词汇表和一组约束。词汇表中包含一些构件和连接件类型,而这组约束指出系统是如何将这些构件和连接件组合起来的。架构风格反映了领域中众多系统所共有的结构和语义特性,并指导如何将各个模块和子系统有效地组织成一个完整的系统。按这种方式理解,软件架构风格定义了用于描述系统的术语表和一组指导构建系统的规则。
对软件架构风格的研究和实践促进了对设计的重用,一些经过实践证实的解决方案也可以可靠地用于解决新的问题。架构风格不变的部分使不同的系统可以共享同一个实现代码。只要系统是使用常用的、规范的方法来组织,就可使别的设计者很容易地理解系统的架构。
例如,如果某人把系统描述为客户/服务器模式,则不必给出设计细节,我们立刻就会明白系统是如何组织和工作的。软件架构风格为大粒度的软件重用提供了可能。然而,对于应用架构风格来说,由于视点的不同,系统设计师有很大的选择余地。要为系统选择或设计某一个架构风格,必须根据特定项目的具体特点,进行分析比较后再确定,架构风格的使用几乎完全是特定的。
9.3.1 软件架构风格分类
讨论架构风格时要回答的问题是:
(1)设计词汇表是什么?
(2)构件和连接件的类型是什么?
(3)可容许的结构模式是什么?
(4)基本的计算模型是什么?
(5)风格的基本不变性是什么?
(6)其使用的常见例子是什么?
(7)使用此风格的优缺点是什么?
(8)其常见的特例是什么?
这些问题的回答包括了架构风格的最关键的四要素内容,即提供一个词汇表、定义一套配置规则、定义一套语义解释原则和定义对基于这种风格的系统所进行的分析。Garlan 和Shaw 根据此框架给出了通用架构风格的分类:
(1)数据流风格:批处理序列;管道/过滤器。
(2)调用/返回风格:主程序/子程序;面向对象风格;层次结构。
(3)独立构件风格:进程通信;事件系统。
(4)虚拟机风格:解释器;基于规则的系统。
(5)仓库风格:数据库系统;超文本系统;黑板系统。
9.3.2 数据流风格
数据流风格的软件架构是一种最常见,结构最为简单的软件架构。这样的架构下,所有的数据按照流的形式在执行过程中前进,不存在结构的反复和重构,就像工厂中的汽车流水线一样,数据就像汽车零部件一样在流水线的各个节点上被加工,最终输出所需要的结果(一部完整的汽车)。在流动过程中,数据经过序列间的数据处理组件进行处理,然后将处理结果向后传送,最后进行输出。
数据流风格架构主要包括两种具体的架构风格:批处理序列和管道-过滤器。
- 批处理序列
批处理风格的每一步处理都是独立的,并且每一步是顺序执行的。只有当前一步处理完,后一步处理才能开始。数据传送在步与步之间作为一个整体。(组件为一系列固定顺序的计算单元,组件间只通过数据传递交互。每个处理步骤是一个独立的程序,每一步必须在前一步结束后才能开始,数据必须是完整的,以整体的方式传递)批处理的典型应用:
(1)经典数据处理;
(2)程序开发;
(3)Windows 下的 BAT 程序就是这种应用的典型实例。
- 管道和过滤器
在管道/过滤器风格的软件架构中,每个构件都有一组输入和输出,构件读输入的数据流,经过内部处理,然后产生输出数据流。这个过程通常通过对输入流的变换及增量计算来完成,所以在输入被完全消费之前,输出便产生了。因此,这里的构件被称为过滤器,这种风格的连接件就像是数据流传输的管道,将一个过滤器的输出传到另一过滤器的输入。
此风格特别重要的过滤器必须是独立的实体,它不能与其他的过滤器共享数据,而且一个过滤器不知道它上游和下游的标识。一个管道/过滤器网络输出的正确性并不依赖于过滤器进行增量计算过程的顺序。
图 9-5 是管道/过滤器风格的示意图。一个典型的管道/过滤器架构的例子是以 UNIX shell 编写的程序。UNIX 既提供一种符号,以连接各组成部分(UNIX 的进程),又提供某种进程运行时机制以实现管道。另一个著名的例子是传统的编译器。传统的编译器一直被认为是一种管道系统,在该系统中,一个阶段(包括词法分析、语法分析、语义分析和代码生成)的输出是另一个阶段的输入。

管道/过滤器风格的软件架构具有许多很好的特点:
(1)使得软构件具有良好的隐蔽性和高内聚、低耦合的特点;
(2)允许设计者将整个系统的输入/输出行为看成是多个过滤器的行为的简单合成;
(3)支持软件重用。只要提供适合在两个过滤器之间传送的数据,任何两个过滤器都可被连接起来;
(4)系统维护和增强系统性能简单。新的过滤器可以添加到现有系统中来;旧的可以被改进的过滤器替换掉;
(5)允许对一些如吞吐量、死锁等属性的分析;
(6)支持并行执行。每个过滤器是作为一个单独的任务完成,因此可与其他任务并行执行。
但是,这样的系统也存在着若干不利因素。
(1)通常导致进程成为批处理的结构。这是因为虽然过滤器可增量式地处理数据,但它们是独立的,所以设计者必须将每个过滤器看成一个完整的从输入到输出的转换;
(2)不适合处理交互的应用。当需要增量地显示改变时,这个问题尤为严重;
(3)因为在数据传输上没有通用的标准,每个过滤器都增加了解析和合成数据的工作,这样就导致了系统性能下降,并增加了编写过滤器的复杂性。
- 批处理序列风格与管道过滤器风格对比
- 共同点:把任务分成一系列固定顺序的计算单元(组件)。组件间只通过数据传递交互。
- 区别:批处理是全部的、高潜伏性的,输入时可随机存取,无合作性、无交互性。而管道过滤器是递增的,数据结果延迟小,输入时处理局部化,有反馈、可交互。批处理强调数据传送在步与步之间作为一个整体,而管理过滤器无此要求。
9.3.3 调用/返回风格
调用返回风格顾名思义,就是指在系统中采用了调用与返回机制。利用调用-返回实际上是一种分而治之的策略,其主要思想是将一个复杂的大系统分解为一些子系统,以便降低复杂度,并且增加可修改性。程序从其执行起点开始执行该构件的代码,程序执行结束,将控制返回给程序调用构件。
调用/返回风格架构主要包括三种具体的架构风格:主程序/子程序;面向对象风格;层次结构。
-
主程序/子程序
主程序/子程序风格是结构化开发时期的经典架构风格。这种风格一般采用单线程控制,把问题划分为若干处理步骤,构件即为主程序和子程序。子程序通常可合成为模块。过程调用作为交互机制,即充当连接件。调用关系具有层次性,其语义逻辑表现为子程序的正确性,取决于它调用的子程序的正确性。 -
面向对象风格
抽象数据类型概念对软件系统有着重要作用,目前软件界已普遍使用面向对象系统。这种风格建立在数据抽象和面向对象的基础上,数据的表示方法和它们的相应操作封装在一个抽象数据类型或对象中。这种风格的构件是对象,或者说是抽象数据类型的实例。对象是一种被称作管理者的构件,因为它负责保持资源的完整性。对象是通过函数和过程的调用来交互的。
图 9-6 是数据抽象和面向对象风格的示意图。

这种风格的两个重要特征为:
(1)对象负责维护其表示的完整性;
(2)对象的表示对其他对象而言是隐蔽的。因为一个对象对它的客户隐藏了自己的表示,所以这些对象可以不影响它的客户就能改变其实现方法。面向对象的系统有许多优点,并早已为人所知:
(1)因为对象对其他对象隐藏它的表示,所以可以改变一个对象的表示,而不影响其他的对象;
(2)设计者可将一些数据存取操作的问题分解成一些交互的代理程序的集合。 但是,面向对象的系统也存在着某些问题:
(1)为了使一个对象和另一个对象通过过程调用等进行交互,必须知道对象的标识。只要一个对象的标识改变了,就必须修改所有其他明确调用它的对象;
(2)必须修改所有显式调用它的其他对象,并消除由此带来的一些副作用。例如,如果 A 使用了对象 B,C 也使用了对象 B,那么,C 对 B 的使用所造成的对 A 的影响可能是料想不到的。
- 层次结构风格
层次系统组织成一个层次结构,每一层为上层服务,并作为下层客户。在一些层次系统中,除了一些精心挑选的输出函数外,内部的层只对相邻的层可见。这样的系统中构件在一些层实现了虚拟机(在另一些层次系统中层是部分不透明的)。连接件通过决定层间如何交互的协议来定义,拓扑约束包括对相邻层间交互的约束。这种风格支持基于可增加抽象层的设计。这样,允许将一个复杂问题分解成一个增量步骤序列的实现。由于每一层最多只影响两层,同时只要给相邻层提供相同的接口,允许每层用不同的方法实现,同样为软件重用提供了强大的支持。
图 9-7 是层次系统风格的示意图。层次系统最广泛的应用是分层通信协议。在这一应用领域中,每一层提供一个抽象的功能,作为上层通信的基础。较低的层次定义低层的交互,最低层通常只定义硬件物理连接。

层次系统有许多可取的属性:
(1)支持基于抽象程度递增的系统设计,使设计者可以把一个复杂系统按递增的步骤进行分解;
(2)支持功能增强,因为每一层至多和相邻的上下层交互,因此功能的改变最多影响相邻的上下层;
(3)支持重用。只要提供的服务接口定义不变,同一层的不同实现可以交换使用。这样,就可以定义一组标准的接口,而允许各种不同的实现方法。
但是,层次系统也有其不足之处:
(1)并不是每个系统都可以很容易地划分为分层的模式,甚至即使一个系统的逻辑结构是层次化的,出于对系统性能的考虑,系统设计师不得不把一些低级或高级的功能综合起来;
(2)很难找到一个合适的、正确的层次抽象方法。
9.3.4 独立构件风格
独立构件风格主要强调系统中的每个构件都是相对独立的个体,它们之间不直接通信,以降低耦合度,提升灵活性。独立构件风格主要包括:进程通讯和事件系统子风格。
- 进程通信架构风格进程通信架构风格:构件是独立的过程,连接件是消息传递。这种风格的特

7231

被折叠的 条评论
为什么被折叠?



