面试官:请聊一聊常见的【软件体系架构】?

1,982 阅读34分钟

软件体系架构(2021.08.10--2021.9.06)

1.概念

软件体系结构(Software Architecture) 包括:

  • 构成系统的设计元素的描述
  • 设计元素之间的交互
  • 设计元素的组合模式以及在这些模式中的约束。

软件体系结构是具有一定形式的结构化元素,即构件的集合,包括处理构件、数据构件和连接构件。处理构件负责对数据进行加工,数据构件是被加工的信息,连接构件把体系结构的不同部分组合连接起来。

简而言之,软件体系结构 = 构件 + 连接件 + 约束

image.png

1.1构件

构件是具有某种功能的可复用的软件结构单元,表示系统中主要的计算元素数据存储

构件是一个抽象的概念,在程序中可以指程序函数、模块、对象、类等。

image.png

1.2连接件

连接件是构件间建立和维护行为关联与信息传递的途径。连接包含下面两种要素:

其中,机制指的实际中的消息传递方式

而协议则决定了 消息的语义理解

image.png

image.png

连接件表示构件之间的交互并实现构件之间的连接。

image.png

2.软件体系结构风格

分四类:从混乱到有序;分布式系统;交互式系统;可适应系统。


从混乱到有序

1.分层模式(Layers)

在软件架构中,分层架构有助于将应用程序划分为多个子任务,其中每组子任务都位于特定的抽象层。

实例:OSI七层模型

经典三层架构自顶向下由用户界面层(User Interface Layer)、业务逻辑层(Business Logic Layer)与数据访问层(Data Access Layer)组成。

三层架构

经典三层架构自顶向下:

  • 用户界面层(User InterfaceLayer)
  • 业务逻辑层(Business Logic Layer)
  • 数据访问层(Data Access Layer)

image.png

领域驱动设计的四层架构

领域驱动设计在经典三层架构的基础上做了进一步改良,在用户界面层与业务逻辑层之间引入了新的一层,即应用层(Application Layer)

image.png

背景

需要分解大型系统

问题

假设你要设计一个系统,其主要特征是需要同时解决高层问题和低层问题,且高层操作依赖问题 于低层操作。在这个系统中,有些部分负责处理低层问题,如硬件陷阱(hardware trap)、传感器输入、读取文件中的比特、读取线路上的电子信号。在谱系的另一端,可能有用户可见的功能(如多用户dungeon游戏的界面)或高层策略(如电话计费)。在典型的通信过程中,请求从高层向低层传输,而响应、到来的数据及事件通知沿相反的方向传输。

结构

结构方面:主要特征是第J+1层只对第J层服务,没有其他层之间的依赖关系

实现

  • 定义将任务划分到不同层的抽象原则
  • 根据抽象准则确定抽象层数
  • 给每层命名分派任务
  • 规范服务
  • 完善层次划分
  • 规范每层的接口
  • 确定各层的结构
  • 规范相邻层之间的通信
  • 将相邻层解耦

效果

优点:

  • 各层可复用
  • 支持标准化
  • 限制了依赖关系的范围
  • 可更换性

缺点:

  • 1.级联问题
  • 2.性能影响

2.管道--过滤器模式(Pipes and Filters)

适合用于处理数据流的系统。每个处理步骤都封装在一个过滤器组件中,数据通过相邻过滤器之间的管道传输。通过重组过滤器,可打造多个相关系统族。

环境: 一个软件的处理流程由多个复杂的过程组成,而且每个处理过程依次执行,前一个处理为后一个处理提供必要的数据,后一个过程需要前一个过程提供数据支持。每个复杂的过程有自己独特的处理逻辑,可以对输入数据全部进行处理,也可以根据自己的特定情况只对一部分数据进行处理,或者作出一些特定的动作,最后输出最终的结果作为软件的执行结果。

背景

处理数据流

问题

假设要打造的系统必须对输入数据流进行处理或转换,以单个组件的方式实现这种系统可能不可行,原因有多个:系统必须由多名开发人员打造;整个系统要完成的任务分多个处理阶段;需求很可能发生变化。 因此,需要提供灵活性,以便能够更换处理步骤或调整处理顺序。提供这样的灵活性后,便可使用既有处理组件打造出一系列系统。设计系统(尤其是连接处理步骤)时,必须考虑如下作用力。

结构

过滤器、管道、数据源、数据接收器

实现

  • 将系统要完成的任务划分为一系列处理阶段,每个阶段都只依赖上一阶段的输出
  • 定义沿管道传递的数据格式
  • 确定如何实现管道连接
  • 设计并实现过滤器
  • 设计错误处理机制
  • 搭建数理流水线

image.png

应用实例

  最典型的应用是编译系统,编译系统主要包括词法分析器,语法分析器,语义分析与中间代码生成器,优化器,目标代码生成器等对源程序进行处理的过程。可以将每个处理过程看做一个过滤器,然后通过管道进行连接,然后就组成了一个编译系统。

image.png

效果

优点:

  • 不需要中间文件,但也可以使用
  • 可更换、重组、重用过滤器
  • 并行处理,效率高

缺点:

  • 共享状态信息开销高昂或缺乏灵活性
  • 错误处理麻烦
  • 数据转换开销

3.黑板模式(Blackboard)

黑板模式应用中的多种不同数据处理逻辑相互影响和协同来完成数据分析处理。就好像多位不同的专家在同一黑板上交流思想,每个专家都可以获得别的专家写在黑板上的信息,同时也可以用自己的分析去更新黑板上的信息,从而影响其它专家。

背景

未找到或找不到确定解决之道的不成熟领域

问题

Blackboard模式解决这样的问题,即没有可行而确定的解决方案将原始数据转换为高级数据结构(如图表或英语词组)。存在这种问题的领域包括视觉识别、图像识别、语音识别和监视等。这种问题具有如下特点:可分解成多个子问题,但每个子问题都属于不同的专业领域。要解决子问题,需要使用不同的表示法和范式。在很多情况下,都没有指导“子问题解决者”如何协同作战的既定策略,这与职责分解形成了鲜明的对比。在职责分解中,按特定顺序启动多个解决步骤。

结构

一个黑板组件、一系列知识源组件、一个控制组件

实现

  • 定义问题
  • 定义问题的解空间
  • 根据子任务将只是划分为专业知识源
  • 定义黑板的词表
  • 规范系统的控制机制
  • 实现知识源

效果

优点:

  • 可以试验
  • 有助于提高可修改行和可维护性
  • 知识源可复用
  • 提高容错能力和健壮性

缺点:

  • 难以测试
  • 不保证得到满意的解
  • 效率低
  • 开发工作量大
  • 不支持并行

分布式系统

4.中间人模式(Broker)

broker架构模式用于实现:通过远程服务调用交互的组件。一个中间人组件负责协调通信(如转发请求)一级传递结果和异常。

背景

分布式的异构系统,其中的组件彼此独立有相互协作

问题

将复杂系统打造成一组彼此分离又相互协作的组件,而不是单个庞大的应用程序,可提高灵活性、可维护性和可修改性。通过将功能划分到多个彼此独立的组件中,系统有望成为分布式和可扩展的。 然而,为让分布式组件彼此通信,必须提供进程间通信机制。如果由组件自己处理通信,系统将面临一些依赖关系和局限性。例如,系统将依赖于使用的通信机制;客户端必须知道服务器的位置;在很多情况下,只能使用一种编程语言来实现解决方案。 还需要添加、删除、更换、激活和查找组件的服务。使用这些服务的应用程序不应依赖于随系统而异的细节,这样即便在异构网络中,也能确保可移植性和互操作性。 从开发人员的角度看,无论是集中式系统还是分布式系统,为它们开发软件的工作应该没什么不同。使用对象的应用程序只能看到该对象的接口,而无需知道该对象的任何实现细节,也无需知道其物理位置。

结构

broker模式包含6类组件: 客户端Client,服务端Server,客户端代理Client_Proxy,服务端代理Server_Proxy,中间人Broker,网桥Bridge。

实现

  • 定义对象模型或使用现在有模型
  • 决定系统应提供什么样的组件互操作性
  • 指定中间人组件应向客户端和服务器提供的API
  • 使用代理对象对客户端和服务器隐藏细节
  • 设计中间人组件
  • 开发IDL编译器

效果

优点:

  • 位置透明性
  • 组件的可修改性、可扩展性、可移植性、可重用性
  • 不同borker系统之间的互操作性

缺点:

  • 效率低
  • 容错性差

交互性系统

5.MVC模式(model-view-contriller)]

用一种业务逻辑、数据、界面显示分离的方法组织代码,将业务逻辑聚集到一个部件里面,在改进和个性化定制界面及用户交互的同时,不需要重新编写业务逻辑。

image.png

背景

人机交互界面灵活的交互式应用程序

问题

用户界面变化频繁。扩展应用程序的功能时,必须修改菜单,让用户能够访问新增的功能;客户可能要求对用户界面做特定调整;系统可能需要移植到采用不同外观标准的平台上;即便将窗口系统升级到新版本也可能需要修改代码。对使用寿命较长的系统来说,其用户界面就是一个移动标吧。 不同用户对用户界面的要求可能相互矛盾:打字员使用键盘将信息输入表单,而经理希望主要通过单击图标和按钮来使用系统。因此,系统应能够轻松地支持多种用户界面。

结构

  • 模型(Model):负责存储系统的中心数据。
  • 视图(View):将信息显示给用户(可以定义多个视图)。
  • 控制器(Controller):处理用户输入的信息。负责从视图读取数据,控制用户输入,并向模型发送数据,是应用程序中处理用户交互的部分。负责管理与用户交互交互控制。

其中,视图和控制器共同构成了用户接口。

实现

  • 将人机交互与核心功能分离
  • 实现变更传播机制
  • 设计并实现视图
  • 设计并实现控制器
  • 设计并实现视图--控制器关系
  • 实现搭建MVC的代码
  • 动态地创建视图
  • “可插入式”控制器
  • 创建视图和控制器的层次结构
  • 进一步降低对系统的依赖性

效果

优点:

  • 一个模型可以多个视图
  • 视图同步
  • “可插入的”视图和控制器
  • 可更换外观
  • 可开发框架

缺点:

  • 更复杂
  • 更新频繁
  • 视图和控制器联系紧密
  • 视图和控制器与模型紧耦合
  • 视图的数据访问效率低下
  • 移植时必须修改视图和控制器
  • 使用交心的用户界面工具时难以遵循MVC

**6.PAC模式(presentation--Abstraction--control)

PAC定义了一种适用于交互式软件系统的结构--由相互协作的只能提组成的层次结构。每个只能提都负责应用程序功能的特定方面,并包含三个组件: 表示组件、抽象组件和控制组件,这将只能提的人机交互方面同核心功能和通信方面分离了。

背景

在agent的协助下开发一个交互式应用程序。

问题

在这种写作的代理体系结构中,为某一特定任务指定一个代理,所有的代理提供所有系统的功能。

1)代理通常维护他们自己的状态和数据;

2) 由于他们各自的人机交互常常差别较大,交互代理提供他们各自的用户接口。

3) 系统随时间变化,他们的表示特性特别易于变化。

结构

1、顶层agent

它应该是整个系统的核心部分。它维护了整个系统的全局数据模型。

1) 抽象组件负责维护整个系统的全局数据模型。

2) 表示组件通常没有什么实际的用处。

3) 控制组件的功能包括:为底层agent提供服务以操作全局数据;维护agent的层次结构;保存用户与系统的交互信息:(?为什么在这里保存)

2、底层agent

底层agent给出了应用领域的一个具体语义概念(比如,柱状图)。

1) 表示组件给出了对应于语义概念的一个具体视图。并保存了视图的信息。

2) 抽象组件的功能和顶层agent抽象组件功能类似,负责维护agent的数据,不同的是,这些数据时这个agent私有的。

3) 控制组件负责表示组件和抽象组件的通信,避免他们的直接依赖。另外,负责和更高层的agent进行通信。

3、中层agent

作用是合作与协作。用于当一个复杂对象由多个底层agent构成,它维护这多个底层agent。

另外一个作用是维护底层agent之间的一致性。例如,协调相同数据的多个视图。

抽象组件维护他的特有数据,表示组件实现了它的用户接口,控制组件具有负责和其他agent通信。

实现

  • 定义应用程序模型
  • 指定PAC层次姐姐狗的总体组织策略
  • 确定顶层PAC智能体
  • 确定提供系统服务的底层PAC智能体
  • 确定用于组合下一层PAC只能提的中间层智能体
  • 将核心功能与人机交互分离
  • 提供外部接口
  • 连接层次结构

效果

优点:

  • 分离关注点
  • 支持修改和扩展
  • 支持多任务

缺点:

  • 系统复杂度高
  • 效率
  • 控制组件复杂

可适应系统

7.微核模式(microkernel)

微核架构(插件架构)适用于必须能够适应不断变化的需求的系统,它将最基本的功能核心与扩展的功能和随客户而异的部分分离。为何还可以充当插座,用于扩展以及协调他们之间的协作。

通常用于实现基于产品的应用,如Eclipse和Firefox。

背景

使用依赖于相同核心功能的编程接口的多个应用程序。

问题

有些应用领域需要应对大量类似的标准和技术,为这样的应用领域开发软件可不简单。著名的例子包括操作系统和图形用户界面等应用程序平台。这种系统的使用寿命通常很长,有时达10年甚至更长。在此期间,新技术会出现,旧技术会改变。因此,设计这种系统需要特别关注下述作用力: * 应用程序平台必须应对硬件和软件的持续发展; * 应用程序平台必须可移植、可扩展、可适应,这样才能轻松地集成新兴技术。 这种应用程序平台的成败还取决于能否运行按既有标准编写的应用程序。为支持范围广泛的应用程序,需要应用程序平台底层功能的多个视图。换而言之,操作系统或数据库等应用程序平台必须能够模拟其所属应用领域的其他应用程序平台。

结构

核心系统(core system)和插件模块(plug-in modules)。

另一种说法:微核,内部服务器(子系统),外部服务器(个性化),客户端,适配器

image.png

实现

  • 分析应用领域
  • 分析外部服务器
  • 将服务分类
  • 划分类别
  • 对于1,找出其完整的操作和抽象集
  • 确定请求传输策略
  • 确定微核组件的结构
  • 微核负责管理所有的系统资源
  • 实现外部服务器
  • 实现适配器

效果

优点

  • 可移植性
  • 灵活性和可扩展性
  • 策略与机制分离
  • 可伸缩性
  • 可靠性
  • 透明性

缺点:

  • 性能低
  • 设计和实现复杂

8.反射模式(reflection)

反射模式提供了一种动态地修改软件系统的结构和行为的价值。他支持对基本方面(如类型结构和函数调用机制)进行修改。采用这个模式,应用程序分两部分:元层和基层。元层提供有关选定系统的属性,让软件能够了解自己;基层包含应用程序逻辑,其实现依赖于元层,修改元素存储的信息将影响基层的行为。

背景

打造天生支持修改的系统

问题

软件系统会随时间的推移不断发展变化。它们必须支持修改,以适应不断变化的技术和需求。设计天生能满足各种需求的系统可能是项令人胆寒的任务,一个不错的解决方案是采用支持修改和扩展的架构,这样系统就能适应不断变化的需求。换句话说,我们希望设计方案能够适应变化和发展。与这个问题相关的作用力有多个。

  • 口修改软件是项繁琐的工作,既容易出错又代价高昂。大面积修改通常涉及众多组件,即便在组件内部进行修改,也可能波及系统的其他部分。对于每项修改,都得仔细地实现和测试。如果软件能够支持并控制更改,修改起来将更有效、更安全。
  • 口可适应软件系统的内部结构通常很复杂。可能变化的方面封装在独立组件中,应用程序服务的实现分布在关系错综复杂的众多小组件中[GHJV95]。为确保这样的系统易于维护,我们倾向于对系统维护人员隐藏这种复杂性。
  • 口确保系统易于修改所需的技术(如参数化、子类化、混合类、复制和粘贴)越多,对系统进行修改时就越麻烦、越复杂。如果有适用于各种修改的统一机制,将更容易使用和理解。 口修改规模各不相同,小至为常见命令提供快捷键,大至根据客户需求调整应用程序框架。口即便是软件系统的基本方面,如组件间通信机制,也可能需要修改。

结构

元层:包含一组元对象,每个元对象都封装了有关基层的某个行为、结构或状态方面的信息。

基层:实现了软件的应用程序,其组件提供了各种系统服务一底层数据模型。还指定了组件之间的协作和结构关系,用户界面也是基层。

实现

  • 定义应用程序模型
  • 找出可能变化的行为
  • 找出发生变化时,不应影响实现的系统方面结构方面
  • 定义元对象
  • 定义元对象协议
  • 定义基层

效果

优点

  • 无需显式地修改源代码
  • 修改软件系统轻而易举
  • 支持众多的不痛类型的修改

缺点

  • 在元层的修改可能带来破坏
  • 增加了组件数量
  • 效率低下
  • 并不支持对软件的所有修改
  • 并非所有语言都支持反射

2、客户机---服务器架构(Client–server model)

简称C/S结构,是一种网络架构,它把客户端 (Client) 与服务器 (Server) 区分开来。每一个客户端软件的实例都可以向一个服务器或应用程序服务器发出请求。

image.png

三层C/S结构(3-Tier C/S Architecture)

§第1层:用户界面GUI—表示层——客户机

§第2层:业务逻辑—功能层——应用服务器

§第3层:数据库—数据层——数据库服务器

优点:

  • 客户机构件和服务器构件分别运行在不同的计算机上,有利于分布式数据的组织和处理。
  • 构件之间的位置是相互透明的,客户机程序和服务器程序都不必考虑对方的实际存储位置。
  • 客户机侧重数据的显示和分析,服务器则注重数据的管理。
  • 构件之间是彼此独立和充分隔离的。
  • 将大规模的业务逻辑分布到多个通过网络连接的低成本的计算机,降低了系统的整体开销。

缺点:

  • 开发成本较高。
  • 在开发C/S结构系统时,大部分工作都都集中在客户机程序的设计上,增加了设计的复杂度。
  • 信息内容和形式单一。
  • 如果对C/S体系结构的系统进行升级,开发人员需要到现场来更新客户机程序,同时需要对运行环境进行重新配置,增加了维护费用。
  • 两层C/S结构采用了单一的服务器,同时以局域网为中心,因此难以扩展到Intranet和Internet。 数据安全性不高。

B/S三层架构:

浏览器/服务器(B/S)是三层C/S风格的一种实现方式

–表现层:浏览器

–逻辑层:• Web服务器• 应用服务器

–数据层:数据库服务器

B/S体系结构的核心是Web服务器,可以将应用程序以网页的形式存放在Web服务器上。

当用户运行某个应用程序时,只需要在可以断的浏览器中输入响应的 URL,向 Web 服务器提出 HTTP 请求。

当Web 服务器接收 HTTP 请求之后,会调用相关的应用程序(Servlets),同时向数据库服务器发送数据操作请求。

数据库服务器对数据操作请求进行响应,将结果返回给Web服务器的应用程序。

image.png

优点:

  1. 客户端只需要安装浏览器,操作简单。
  2. 运用HTTP标准协议和统一客户端软件,能够实现跨平台通信。
  3. 开发成本比较低,只需要维护Web服务器程序和中心数据库。

缺点:

  • 个性化程度比较低,所有客户端程序的功能都是一样的。
  • 客户端数据处理能力比较差。
  • 在B/S结构的系统中,数据提交一般以页面为单位,动态交互性不强,不利于在线事务处理。
  • B/S体系结构的可扩展性比较差,系统安全性难以保障。
  • B/S结构的应用系统查询中心数据库,其速度要远低于C/S体系结构。

3.设计模式

Whole-Part(整体一部分)、Master-Slave(主一从)、Proxy(代理)、Command Processor(命令处理器)、 View Handler(视图管理者)、 Forwarder-Receiver(转发者一接收者)、Client-Dispatcher-Server(客户端一分派器一服务器)和Publisher-Subscriber(发布者一订问者)等

设计模式为中型模式,规模比架构模式小,但所处的层次比编程语言特定的成例高。使用设计模式不会影响软件系统的基本结构,但可能给子系统的架构带来重大影响。 像架构模式一样,我们将设计模式也分为几类。

  • 结构分解模式。这类模式有助于以恰当的方式将子系统和复杂组件分解为一系列相互协作的部分。据我们所知,这类模式中最常见的是 Whole-Part,它非常适合组织复杂的组件。
  • 工作组织模式。这类模式定义组件如何相互协作,以解决复杂的问题。我们将介绍其中的Master-Slave,它可帮助组织必须能够容错或计算必须精确的服务,还有助于将服务划分为多个部分,这些部分彼此独立,可同时执行。
  • 访问控制模式。这类模式监视并控制对服务或组件的访问。我们将介绍其中的Proxy,借助它,客户端能够与组件的代表(而非组件本身)通信。
  • 管理模式。这类模式处理一系列同质对象、服务和组件,我们将介绍其中两个:Command Processor和View Handler,其中前者致力于管理和调度用户命令,后者描述了如何管理软件系统中的视图。
  • 通信模式。这类模式帮助统筹组件间通信。下面两个模式致力于解决进程间通信问题:Forwarder-Receiver致力于点对点通信,而Client-Dispatcher-Server描述了如何在客户端服务器模型中实现位置透明的通信。
  • Publisher-Subscriber模式有助于确保协作组件的数据一致,与[GHJV95]介绍的Observer模式是一回事,因此我们只介绍该模式的精髓,并重点介绍其重要变种Event Channel。

1.结构分解模式

1.1、Whole-Part(整体一部分)模式

Whole-Part有助于将组件聚合成语义整体。聚合组件(Whole)封装组成它的组件(Part),统筹它们之间的协作,并提供访问其功能的通用接口。从外部不能直接访问Part组件。

背景:

实现聚合对象

问题:

几乎在每个软件系统中,都存在由其他对象组成的对象。就拿化学模拟系统中的分子对象来说吧,可将其实现为一个由不同原子对象组成的图。这种聚合对象表示的并非一组松耦合的组件,相反,它们是一个整体,而不仅仅是其组成部分的集合。在这个例子中,分子对象有属性(如其化学性质)和方法(如旋转),这些属性和方法针对的是分子这个语义整体,而不是组成分子的原子。这个示例说明了一种典型情况:聚合展现了其组成部分没有或不那么显而易见的行为,即组合带来了新行为。这种行为被称为衍生行为(emergent behavior)。例如,仅通过分析分子的各个原子,并不能判断出它能参与哪些化学反应。 模拟这种结构时,需要平衡下述作用力。

  • 要么使用既有对象组合成复杂对象,要么将复杂对象分解为更小的对象。这有助于改善可重用性和可修改性以及将对象重组为其他类型的聚合。
  • 在客户端看来,聚合对象是个整体,不能直接访问其组成部分。

结构:

1.透明组合模式

image.png

2.安全组合模式

image.png

实现:

  • 设计whole的共有接口
  • 将whole划分为part或使用现有对象合成它
  • 如果采用自下而上的方式,从组建库或类库选择现有part,并确定他们如何协作。如果现有part无法提供whole的所有功能,确定新增的part,并将其与其他part继承起来。为实现缺少的part,可能需要自上而下的方式
  • 如果采用自上而下的方式,将whole的服务划分成相互的小服务,二这些服务将对应的不用的part。
  • 使用part服务来定义whole的服务
  • 实现part
  • 实现whole

效果:

优点:
  • 可修改part
  • 分离关注点
  • 可重用性
缺点:
  • 间接导致效率 低下
  • 分解part的工作很复杂

2.工作组织模式

2.1、Master-Slave(主一从)模式

设计模式 Master-Slave 有助于改善容错性以及计算的并行性和准确度。一个主组件培工作分配给多个相同的从组件,并根据这些从组件返回的结果计算最终结果。

背景:

将工作分为多个语义上等价的子任务

问题:

“分而治之”是解决众多问题的常用策略:将工作均分为多个子任务,并分别处理这些子任务;再根据每个子任务的处理结果计算最终结果。实现这种结构时,将面临多个作用力。口不应让客户端知道计算是基于“分而治之”策略的。

  • 无论是客户端还是子任务的处理,都不依赖于划分工作和计算最终结果的算法。
  • 如果每个子任务的处理方式都不同,但从语义上说又都是等价的,将大有碑益,如提高计算的准确度。
  • 有时候(如在使用有限元方法的模拟应用程序中),需要协调子任务的处理。

结构:

image.png

实现:

  • 分工
  • 合并子任务
  • 规范主组件和从组件之间的协作
  • 根据钱一步指定的规范实现从组件

效果:

优点:
  • 可更换性和可扩展性
  • 分离关注点
  • 效率
缺点:
  • 可行性
  • 依赖于计算机
  • 难以实现
  • 可移植性

3.访问控制

3.1、Proxy(代理)模式

代理模式让客户端与代表而非组件本身通信。引入这样的代理可达成很多目的,如提高效率、简化访问以及进制为授权的访问

背景:

客户端需要访问另一个组件提供的服务,直接访问从技术上可行,但可能不是最佳的。

问题:

直接访问组件场次是不妥当的。我们不想在客户独爱一应变吗方式指定组件的物理位置,另外不收限制的直接访问组件可能效率低下甚至不安全,因此需要额外的控制机制。

  • 对客户端和组件来说,访问组件的方式必须高效、划算、安全。
  • 对客户端来说,对组件的访问必须透明而简单。具体地说,调用行为和语法应与调用直接访问的组件时一样。
  • 客户端应深知访问远程服务可能带来的性能和财务开销。完全透明可能导致不同服务的成本差异变得模糊。

结构:

原件实现特定服务、客户端负责执行特定任务,代理提供与原件相同的接口、抽象原件提供了代理和原件实现的接口。

image.png

image.png

实现:

  • 找出与组件访问控制相关的所有职责
  • 用一个抽象类定义代理和原件接口都有的部分
  • 实现代理的函数
  • 让原件和客户端不在承担已有代理承担的职责
  • 消除客户端与原件的直接关系

效果:

优点:
  • 效率更高,开销更低
  • 将客户端与服务器组件文职分离
  • 将管理代码与功能分离
缺点:
  • 间接降低了效率
  • 无畏的复杂策略

4.管理模式

4.1、Command Processor(命令处理器)模式

Command Processor 将服务的请求和执行分开。命令处理器组件将求救作为独立的对象进行管理,调度起执行并提供额外的服务,如存储请求对选哪个一边以后能够撤销请求。

背景:

应用程序需要灵活可扩展的用户界面,或提供与执行请求(图调度或撤销)相关的服务。

问题:

除系统核心功能外,你经常需要实现与执行用户请求相关的服务。这样的例子包括撤销、重做、将请求编组的宏、将操作写入日志以及调度和挂起请求等。 解决方案必须消解下述作用力:

  • 不同用户喜欢以不同的方式使用应用程序;
  • 改进应用程序时不应导致既有代码无法正常运行;
  • 必须以一致的方式为所有请求实现额外服务,如撤销。

结构:

抽象命令、控制器、命令处理器、供应者

image.png

实现:

  • 定义抽象命令接口
  • 为应用程序支持的没累请求设计命令组件
  • 提供组合过个相连命令的宏命令
  • 实现控制器组件
  • 实现访问命令处理器的额外服务
  • 实现命令处理器组件

效果:

优点:
  • 请求激活方式灵活
  • 请求的功能和数量灵活
  • 与执行相关的服务抑郁便携
  • 应用程序级可测试性
  • 并发性
缺点:
  • 影响效率
  • 命令类可能太多
  • 获取命令参数的复杂性

4.2、View Handler(视图管理者)模式

View Handler有助于管理软件系统提供的所有视图。视图管理这组件让客户端能够打开、操作个关闭视图,他还负责协调视图之间依赖关系以及统筹视图更新。

背景:

提供应用程序特定数据的多个视图或允许用户同事处理多个文档的软件系统

问题:

支持多个视图的软件系统通常需要包含管理这些视图的功能。用户希望能够方便地打开、操作和关闭视图,如窗口及其内容。视图必须协调一致,因此对一个视图所做的修改必须自动传播到相关视图。这种问题的解决方案需要消解多个作用力。

  • 无论是在用户还是系统的客户端组件看来,管理多个视图都轻而易举。
  • 各个视图的实现不能相互依赖,也不能与管理视图的代码混在一起。
  • 在系统的生命周期内,视图的实现可能发生变化,还可能添加新的视图类型。

结构:

视图管理者、抽象视图、具体视图、供应者

image.png

实现:

  • 确定所需的视图
  • 定义所有视图通用的接口
  • 实现视图
  • 定义视图管理者

效果:

优点:
  • 以统一的方式管理视图
  • 视图的可扩展性和可修改性
  • 以应用程序特定的方式协调视图
缺点:
  • 适用范围有限
  • 影响效率

5.通信模式

5.1、 Forwarder-Receiver(转发者一接收者)模式

Forwarder-Receiver利用对等交互模型让软件系统能够透明地进行进程之间通信。他通过引入转发者和接受者将对等体育底层通信机制解耦。

背景:

对等通信

问题:

为打造分布式应用程序,一种常见的方式是利用低级进程间通信(IPC)机制,如TCPAP、套接字或消息队列。几乎所有操作系统都提供了这些机制,相比高级机制(如远程过程调用)。它们的效率高得多。然而,如果采用这些低级机制,分布式应用程序通常将依赖于底层操作系统和网络协议。使用特定IPC机制会降低解决方案的可移植性,限制系统支持异质环境的能力,且以后难以更换IPC机制。 在需要平衡下述作用力时,模式Forwarder-Receiver可助一臂之力:

  • 必须能够更换系统的通信机制;
  • 组件按对等模型协作,发送方只需知道接收方的名称;
  • 对等体之间的通信不应严重影响性能。

结构:

转发者、接收者和对等体

实现:

  • 定义名称到地址映射
  • 定义要在对等体和转发者之间使用的消息协议
  • 选择通信机制
  • 实现转发者
  • 实现接收者
  • 实现应用程序的对等体
  • 实现启动配置

效果:

优点:

搞笑的进程之间通信

封装来了IPC机制

缺点:

不能灵活的重新配置组件

5.2、Client-Dispatcher-Server(客户端一分派器一服务器)模式

Client-Dispatcher-Server 在客户端和服务器之间添加了一个中间层——分派器组件。它利用明晨服务了位置透明性,并隐藏了在客户端和服务器之间简历通信连接的细节。

背景:

继承一组分布式服务器的软件系统,这些服务器位于本地或分布在网络中

问题:

使用分布在网络中的服务器的软件系统必须提供在服务器之间通信的途经。在很多情况下,根据使用的通信机制,组件之间可能需要先建立连接,然后才能通信。然而,应将组件的功能核心与通信机制细节分开。客户端不需要知道服务器的位置,这样可动态地移动服务器,还让系统能够抵御网络故障和服务器故障。 必须平衡下述作用力:

  • 使用服务的组件不应依赖于服务提供方的位置;
  • 在服务的客户端,应将功能核心代码与用于连接到服务提供方的代码分开。

结构:

  • 客户端的职责是执行领域特定任务
  • 分派器提供客户端和服务器简历通信信道的功能。
  • 服务器提供服务

实现:

  • 将应用程序组件分为服务器和客户端
  • 确定需要那些通信机制
  • 确定组件之间交互协议
  • 决定如何给服务器命名
  • 设计并实现分派器根据指定的解决方案以及有关分派器接口方面的决策实现客户端和服务器组件。

效果:

优点:
  • 服务器可更换
  • 位置透明性
  • 可重新配置
  • 容错
缺点:
  • 间接性和显式简历连接降低了效率
  • 对分派器借口变化敏感

5.3、Publisher-Subscriber(发布者一订问者)模式

Publisher-Subscriber 有助于让相互协作作用的组件的状态保持同步。为此,它实现了单项变更传播:发布者的状态变化时可通知任意数量的订阅者。

背景:

/

问题:

一个地方的数据发生变化时,将影响大量依赖于这项数据的组件,这种情形很常见。典型的例子是用户界面元素:内部数据元素发生变化时,必须更新依赖于这些数据的所有视图。为解决这种问题,可通过直接调用来传播变更,但这种解决方案既不灵活又不可重用。我们需要找到一种更通用、适用于众多情形的变更传播机制。 解决方案需平衡如下作用力。

一个组件的状态发生变化时,必须通知其他组件。

  • 依赖组件的数量和身份预先并不知道或可能随时间的推移而变化。
  • 让依赖组件显式地轮询不可行。

结构:

/

实现:

/

效果:

/