【笔记】常见的架构风格
目录1. 传统的架构风格1.1. 数据流风格1.2. 调用/返回风格1.3. 独立构件风格1.4. 虚拟机1.5. 仓库风格2. 基于连接件的架构风格划分2.1. 数据流风格2.2. 调用/返回风格2.3. 独立构件风格2.3.1. 思考2.3.2. C2风格(Component and Connector)3. 基于场景的架构风格划分4. 特定领域架构模型
风格即模式:3类基本的架构风格(数据流、调用返回、独立构件); 应用场景模型:我们平常说的“架构”概念,是一种场景模型,常用于解决特定的问题。
脑图链接:软件架构
软件体系结构风格是描述某一特定应用领域中系统组织方式的惯用模式。体系结构风格定义一个系统家族,即一个体系结构定义一个词汇表和一组约束。词汇表中包含一些构件和连接件类型,而这组约束指出系统是如何将这些构件和连接件组合起来的。也就是说,架构体系都是以“构件”的思路进行软件实现的。
体系结构风格反映了领域中众多系统所共有的结构和语义特性,并指导如何将各个模块和子系统有效地组织成一个完整的系统。对软件体系结构风格的研究和实践促进对设计的重用,一些经过实践证实的解决方案也可以可靠地用于解决新的问题。例如,如果某人把系统描述为“客户/服务器”模式,则不必给出设计细节,立刻就会明白系统是如何组织和工作的。
1. 传统的架构风格
依据David Calvert在1996年给出了一份架构风格/模式的清单,架构风格包括了:
数据流系统——批处理,管道-过滤器。
调用-返回系统——主程序和子程序,面向对象系统,分层。
独立组件——通信过程,事件系统。
虚拟机——解释器,基于规则的系统。
以数据为中心的系统(仓库)——数据库,超文本系统,黑板。
1.1. 数据流风格
面向数据的架构风格,软件的处理粒度是赤裸裸的“数据”,而不需对数据进行任何的“包装”。
批处理序列
组件为一系列固定顺序的计算单元(独立程序),组件间只通过数据传递交互。数据计算单元的执行必须在前一单元完全结束后才能开始,数据以整体的方式传递。
管道/过滤器
每个构件都有一组输入和输出,构件读取输入的数据流,经过内部处理,然后产生输出数据流。这个过程通常通过对输入流的变换及增量计算来完成,包括通过计算和增加信息丰富数据,通过浓缩和删除精炼数据,通过改变记录方式转化数据,递增地转化数据等。在输入被完全消费之前,输出便产生了。这里构件被称为过滤器,连接件就是数据流传输的管道,将一个过滤器的输出传到另一个过滤器的输入。
此风格要求过滤器必须是独立的实体,它不能与其它的过滤器共享数据,而且一个过滤器不知道它上游和下游的标识。一个管道/过滤器网络输出的正确性并不依赖于过滤器进行增量计算过程的顺序。
总结
优势:
使得软构件具有良好的隐蔽性和高内聚、低耦合的特点;
构件之间的组合、重用十分简单,易于拼接成业务功能块;
限制:
不适合处理交互的应用。由于业务功能块是按照结构化的流程设计的,所以只适用于处理特定的逻辑流程。当需要增量地显示改变时,这个问题尤为严重。
数据由于没有任何封装,传输上没有通用的标准,每个过滤器都增加了解析和合成数据的工作,这样就导致了系统性能下降,并增加了编写过滤器的复杂性。
1.2. 调用/返回风格
主程序 & 子程序
采用单线程控制,把问题划分为若干处理步骤,构件即为主程序和子程序。子程序通常可合成为模块。过程调用作为交互机制,即充当连接件。调用关系具有层次性,其语义逻辑表现为子程序的正确性,取决于它调用的子程序的正确性。
面向对象
这种风格的构件是对象。对象是抽象数据类型的实例。在抽象数据类型中,数据的表示和它们的相应操作被封装起来。对象的行为体现在其接受和请求的动作。连接件即对象间交互的方式,对象是通过函数和过程的调用来交互的。这种结构风格中包含有封装、交互、多态、集成和重用等特征。
层次结构
层次系统组织成一个层次结构。连接件通过决定层间如何交互的协议来定义,拓扑约束包括对相邻导间交互的约束。这个风格将大的问题分解为若干个渐进的小问题,逐步解决,隐藏了很多复杂度。修改一层,最多影响两层,而通常只能影响上层。上层必须知道下层的身份,不能调整层次之间的顺序。
优点:
支持基于抽象程度递增的系统设计,使设计者可以把一个复杂系统按递增的步骤进行分解;
支持重用。只要提供的服务接口定义不变,同一层的不同实现可以交换使用。
1.3. 独立构件风格
面向消息的通讯架构(进程间通信)
构件是独立的过程,连接件是消息传递。这种风格的特点是构件通常是命名过程(进程),消息传递的方式可以是点到点、异步和同步方式及远过程调用(RPC)等。在这种架构中,消息的传递目标是显式声明的——明确指向另外一个构件。
事件驱动架构
构件不直接调用一个过程,而是触发或广播一个或多个事件。系统中其他构件中的过程在一个或多个事件中注册,当一个事件被触发,系统自动调用在这个事件中注册的处理机制。一个事件的触发就导致了另一个模块中过程的调用——这本身属于一种异步机制的实现(实际上有些事件的响应是以同步方式实现的)。
从体系结构上说,这种风格的构件是一些模块,这些模块既可以是一些过程,又可以是一些事件的集合。过程可以用通用的方式调用,也可以在系统事件中注册一些过程,当发生这些事件时,过程被调用。
构件之间交互的连接件往往是以过程之间的隐式调用(Implicit Invocation)来实现的。基于事件的隐式调用风格的主要优点是为软件重用提供了强大的支持,为构件的维护和演化带来了方便;其缺点是构件放弃了对系统计算的控制。
优点:
为软件重用提供了强大的支持。当需要将一个构件加入现存系统中时,只需将它注册到系统的事件中,十分灵活。
缺点:
构件放弃了对系统计算的控制。一个构件触发一个事件时,不能确定其它构件是否会响应它。而且即使它知道事件注册了哪些构件的构成,它也不能保证这些过程被调用的顺序;
既然过程的语义必须依赖于被触发事件的上下文约束。
1.4. 虚拟机
解释器
一个解释器通常包括完成解释工作的解释引擎,一个包含将被解释的代码的存储区,一个记录解释引擎当前工作状态的数据结构,以及一个记录源代码被解释执行的进度的数据结构。具有解释器风格的软件中含有一个虚拟机,可以仿真硬件的执行过程和一些关键应用;其缺点是执行效率较低。
基于规则的系统
基于规则的系统包括规则集、规则解释器、规则/数据选择器及工作内存。
1.5. 仓库风格
在仓库风格中,有两种不同的构件:中央数据结构(仓库)说明当前状态,独立构件在中央数据存贮上执行。
数据库架构(共享数据)
数据库架构是仓库风格最常见的形式。构件主要有两大类,一个是中央共享数据源,保存当前系统的数据状态;另一个是多个独立处理元素,处理元素对数据元素进行操作。例如二层C/S架构中不同的服务项对服务数据库的访问模型。
黑板架构
黑板架构包括知识源、黑板和控制3个部分。
知识源包括若干独立计算的不同单元,提供解决问题的(与应用程序相关的)知识,知识源响应黑板上的变化,也只修改黑板 ==> 独立算法模块;
黑板是一个全局数据库,包含问题域解空间的全部状态。黑板数据是按照与应用程序相关的层次来组织的解决问题的数据,知识源通过不断地改变黑板数据来解决问题。
控制逻辑:控制完全由黑板的状态驱动,黑板状态的改变决定使用的特定知识。
黑板通常应用在对于解决问题没有确定性算法的系统中,例如信号处理、问题规划及编译器优化等软件系统的设计中。
超文本系统
构件以网状连接方式相互连接,用户可以在构件之间进行按照人类的联想思维方式任意跳转到相关构件。超文本是一种非线性的网状信息组织方法,它以结点为基本单位,链作为结点之间的联想式关联。超文本系统通常应用在互联网领域。
不同的人划分过不同的架构模型,而每每觉得,如果拿来两本书中所描述的架构模型,他们说的完全不在一个维度上,因为分类方式不同,得到的结果也不同,甚至同一套模型,在两本书里也得到了不同的名字……
我梳理了自己目前所理解到的所有架构模型,并按照自己的理解程度,重新进行了分类得到了一组架构图,现在写下了。希望大家能多提意见。我不一定完全赞同你们的观点,但真理总是越辩越清,辩论不伤和气,只为共同进步!
2. 基于连接件的架构风格划分
前面已经提到,“架构”是一种基于“组件”的软件体系模型。在这个模型中,存在两类基本的元素:构件 + 连接件。很明确的,构件是计算单元(实体);而连接件则存在多种的形式——构件间如何实现连接和交互,是各种架构在处理问题上的本质区别(或者说是问题模型的区别)。
2.1. 数据流风格
连接件即为传输的数据,而构件之间只通过数据传递交互。“管道/过滤器”风格相比于“批处理”,其连接件(即“管道”)是以流的形式传输的数据,而不是一个完整的数据体。
2.2. 调用/返回风格
过程调用作为交互机制,即充当连接件的角色。构件之间通过主动或被动的显示调用执行交互。
主程序/子程序风格中,构件即为主程序和子程序。面向对象更没的说,构件即为不同的对象。而分层架构模型则是将不同层次的功能集合作为构件,构件间通过接口调用,实现交互。
还有两种流行的架构模式,也可以划归到“主程序-子程序”的返回/调用风格中——“插件式”的微内核架构和RPC(远程过程调用)。
主程序/子程序的架构风格一般是通过本地管道执行调用,插件架构通过系统级调用插件模块,RPC执行调用的方式是通过socket。连接件实现通信的方式可能不同,但在宏观上,他们都在调用其他模块的已有功能块。
2.3. 独立构件风格
连接件是消息或事件,以显示或隐式的方式在构件间传递交互。
“进程通信”架构中,构件通常是命名过程(所谓过程,即功能实现,可以是函数、程序体或类对象),连接件是消息传递,传递方式可以是点对点、同步或异步的方式,以及RPC远程过程(方法)调用等。
事件驱动的系统,也称为“基于事件的隐式调用”架构,构件不直接调用一个过程,而是触发或广播一个或多个事件。连接件即为事件(消息的一种表现形式)。之所以成为事件,是因为它会自动触发其他构件的处理动作,改变构件的状态和行为。从宏观上看,构件之间是通过“隐式调用”实现交互的。
2.3.1. 思考
个人认为,“独立构架风格”已经带有很强的“场景”适用性了——由于独立构件风格中的连接件是以“消息或事件”的形式存在的,而一般情况下进程内部很少(或者说非必须)通过消息传递信号【当然这也不一定,如果需要多个层次或对象间的调用,比如GUI中的事件机制】,往往“独立架构”风格是用在进程间或分布式环境中的通讯机制上的。
2.3.2. C2风格(Component and Connector)
C2是针对通信领域的一种场景架构模型。C2架构应该说是对独立架构的一种拓展,或是重新定义——它以“消息”的概念替代了传统意义上的连接件,同时将消息处理节点从构件中独立出来作为一种基本类型,称为“连接件”。
构件:消息处理的实体;
消息:包括通知消息和请求消息,分别以自上而下和自下而上的方式传递;
连接件:负责消息路由与广播,同时也对消息进行过滤。
另外,它还定义了构件与连接件的交互规则,如下图所示:
而这种交互方式,同“基于消息的进程间通讯架构”和“事件驱动架构”一样,几乎定格成了一种默认形式,在所有的通讯体系中都有所应用。故而称之为“风格”也不为过。
3. 基于场景的架构风格划分
相比于特定领域架构模型,它没有特定的问题域,而是在不同的领域中,可能存在共性的应用场景,大致可分为虚拟机、仓库、C2、微内核等架构风格。
4. 特定领域架构模型
常见的领域包括:分布式、消息通信、WebService、企业级架构等。