分布式模式

分布式定义:将一个完整的服务,按照业务功能,拆分成一个个独立的子服务。这些子服务能够独立运行在部署的环境中,它们之间通过RPC方式通信。

模式:模式是指从生产经验和生活经验中经过抽象和升华提炼出来的核心知识体系。模式(Pattern)其实就是解决某一类问题的方法论。把解决某类问题的方法总结归纳到理论高度,那就是模式。模式是一种指导,在一个良好的指导下,有助于你完成任务,有助于你作出一个优良的设计方案,达到事半功倍的效果。而且会得到解决问题的最佳办法。

模式语言:模式是软件架构中的词汇,而模式语言则在某种程度上相当于语法和风格。模式语言定义了一系列互相联系的模式,一个模式——可选或者必须–释放依赖于另一个模式–形成一个树或者有向图,从而一一种特别的方式详细描述和设计,响应特定的驱动因素,并根据情况选择适当的解决办法。

模式语言的结构和内容

我们把分布式计算的模式语言包含一百多个模式,这里我们按照问题域划分,介绍10组问题域。每个问题域描述一个和构造分布式系统相关的特定技术主题。问题域的作用是为了使得模式语言和其模式更容易被理解:将解决相关问题的模式放在一个公共且范围明确的环境中讨论和讲解。

1.从混沌到结构

这个问题目的是从最初的需求和约束条件中提取出粗粒度的软件结构,将其划分为待开发系统的有实际意义的各个部分。这里涉及了分布式计算模式语言根模式和切入点。

首先软件结构必须对系统应用有意义的。其次考虑可变性方便拓展。这里提到Domain Model:领域模型是一种特殊的业务模型,它分析范围是整个行业,抽象出行业里共性和内在规律性的业务,比业务模型更加抽象,它不属于软件开发范畴的概念,与软件开发无关。领域模型是一种分析模型,在软件开发过程分析阶段用于分析如何满足系统功能性需求,属于软件开发范畴,在UML中主要使用类图来描述领域模型。

光从应用领域可见角度划分分布式软件系统核心并不能保证定义出一个可行的基线架构。一方面软件系统包括许多组件,并表现出许多与系统无关的属性和组件交叉问题。另一方面,除了满足客户需求,我们还需要关注可维护性,可理解性,扩展性,可测性。还有如下问题需要面对:

1.应用怎么样与环境交互。2.应用处理是怎么组织的3.应用必须支持什么样的变化4.应用预期寿命是多少。

因此,我们的分布式计算模式语言包含九个全局性模式帮助领域模型转化为技术架构。

1.Layer模式帮助我们将应用结构分解为子任务群,每个子任务群是按照特定的抽象层次,粒度或者其他标准划分的。

2.Model-View-Controller模式将交互式应用分解为三个部分。Model包含核心功能和数据,View用于展示用户信息,controller部分处理用户输入。

3.Presentation-Abstraction-Control按照合作代理的层次结构来定义交互式软件系统的结构。

4.Microkernel模式将最小的功能核心与其它扩展功能以及用户定制部分分离。

5.Refelection模式提供了一种动态改变软件系统结构和行为的机制。

6.Pipes and Filters提供了可以处理数据流的结构。

7.ShareRepository模式帮助我们结构化那些功能和协作均由数据驱动的应用。

8.BlackBoard模式几个专门的子系统户籍起来提供一个可能的局部近似方案解决没有已知方案的。

9.Domain Object模式将自我完备的连贯功能和基础性责任封装成定义良好的实体。通过一个或者多个Explicit interface提供功能并其隐藏内部结构。

2.分布式基础设施

如果只考虑应用、主操作系统(host operating system)和网络,我们将很难满足复杂的分布式系统的要求,比如可伸缩性、可靠性等。应用应该只关注“业务逻辑”,而不是繁杂的底层基础实现(plumbing), 操作系统和网络应该分别关注终端系统( endsystem)的资源管理和通信协议的处理。为满足其他关键方面的需求,这里介绍了三个与中间件相关的模式。所谓中间件,就是分布式基础设施软件,它可以为应用屏蔽来自于操作系统和网络的那些固有的或难以预料的复杂性。

(1)Messaging (消息传递)模式用于组织这样的分布式软件系统:其不同的服务间通过交换消息来相互作用。有一系列相互连 接的Message Channel和Message Router管理着跨网络的不同服务间的消息交换,包括传递请求和应答消息,消息中含有正常信息、元数据和错误信息。

(2)Publisher -Subscriber (发布者-订阅者)模式用于组织这样的分布式软件系统:其不同的服务和组件间通过一对多 的关系异步地交换事件来相互作用。通常,事件的Publisher和Subscriber并不彼此知道对方。Subscriber只 负责消费事件,并不关心事件的Publisher是谁。类似地,Publisher只 负责供应事件,不关心谁订阅了这些事件。

(3)Broker (经纪人)模式用于组织这样的分布式软件系统:其不同的组件间通过远程方法调用来相互作用。一个代理管理器管理着组件间互操作的各个关键方面,从派发请求到传递结果和异常等。

3.事件分离和分发

分布式的核心都是处理和响应网络中收到的事件。这里介绍四个模式描述分布式网络系统中的发起,接收,分离分发和处理事件的不同方法。

也许中间件平台为应用提供了更复杂的通信模型,如请求/响应操作或异步消息,但分布式计算从根本_上来说仍然是事件驱动的。事件驱动的软件所要面对挑战与一般的“自主”(selfdirected)控制流软件有所不同。面对的问题是:事件的异步到达,多个事件的并发到达,事件到达的不确定性,多种事件类型。解决问题的模式如下:

(1)Reactor (反应器)模式允许事件驱动软件分离和分发从一个或多个客户端传递到应用的服务请求。

​ (2)Proactor (前摄器)模式允许事件驱动软件有效分离和分发由异步操作完成所触发的服务请求,从而获得性能和并发性的提升,避免它的某些不足。

​ (3)Acceptor-Connector (接受器连接器)模式将网络系统中互操作的对等服务之间的连接和初始化与连接和初始化之后的对等服务处理相分离。

​ (4)Asynchronous Completion Token (异步完成令牌)模式允许事件驱动软件能高效地分离和处理异步服务调用的响应。

4.接口划分

确定组件接口是软件项目中非常重要的活动。接口应当清楚地反映组件的职责和使用协议,为客户端提供有意义的服务,并且让客户端避免由于组件实现的变动和升级而受到影响。否则,组件将会变得难以使用,而且彼此之间的协作也会变得很复杂。这里给出了11个模式来具体说明怎样设计具有良好定义的接口,以满足上述要求。首先考虑以下问题:组件职责和约定规范,质量属性,可表达性和简洁性,可表达性和简洁性。

划分接口的模式如下:

(1)Explicit Interface模式将组件使用和实现细节分离。客户端只依赖于组件接口定义的契约,而不依赖于组件的内部设计、实现规范、位置、同步机制和其他实现细节。

(2)Extension Interface模式允许组件导出多个接口,在开发人员扩展或修改组件功能时避免接口膨胀和破坏客户端代码。

(3)Introspective Interface 模式提供了一个辅助接口,以支持客户端访问组件类型、功能、公开接口、内部接口、行为,以及运算状态信息。客户端或应用之外的工具可以使用这些信息来监控组件或控制组件的使用。

(4)Dynamic Invocation Interface (动态调用接口)模式提供了一个辅助接口,以允许客户端动态地调用组件方法。它支持在运行时组织调用而不是在声明时选择接口。

(5)Business Delegate (业务代表)模式对使用组件的客户端封装了与访问远程组件相关的基础设施的各方面,如查找、负载平衡和网络错误处理等。Business Delegate保证了在分布式应用中调用组件时的位置透明性。

(6)Proxy模式使得组件的客户端能够与Proxy而不是组件本身一进行透明的通信。Proxy能达到多个目的,包括简化客户端编程、提高效率,以及防止未授权的访问。

(7)Facade (外观)模式为子系统中的一-套接口提供了一个统一的、高层次的接口,从而使得子系统更易于使用。

(8) Combined Method (组合方法)模式将通常一起使用的方法放在 一起,形成一个方法来确保正确性,并提高在多线程和分布式环境中的效率。

(9)Iterator (迭代器)模式提供了顺序访问聚合元素的一种方式,它的好处是不需要暴露组件的内部表现。

(10)Enumeration Method模式将聚合(aggregate) 组件上的迭代对组件中每个元素执行一次操作封装成聚合上的一个方法。其目的是减少外部迭代方式多次对聚合中的元素进行独立访问的开销

(11)Batch Method模式将重复访问的聚合元素合并在一起,以减少单个元素的多次访问开销。

5.组件划分

组件是实现的构建块(building block),它为客户端提供定义良好的服务。通常,客户端并不关心这些服务是如何实现的。组件的使用者当然可以得益于组件的黑盒特性,但是组件的开发者却不得不面对组件内部设计的各种挑战。因此,本章提供了6个模式帮助读者构建组件的实现。这些模式所关注的是组件的分解和对分布式系统各种组件部署情形的支持。

基于组件的软件开发是构建现代软件系统的关键技术。其核心的思想是,软件可以由定义良好的构建块组成,每个模块通过接口提供一一个特定的、内聚的、完备的服务。组件及其可组合性是基于它们的强封装结构的,而且,一般来说在绑定时间和绑定位置都有很大的选择空间。实现组件的问题在于需要考虑以下因素:组件划分,组件质量,组件灵活性,对组件功能进行分布,组件实现内部的并发和并行。我们介绍六个模式解决上面的问题。

(1)Encapsulated Implementation(封装实现)模式提供了一种基本的、典型的组件设计方式,使得组件既能够满足其接口契约职责,又不会通过接口泄漏其实现,因为通过配置或者创建选项所暴露的信息已经降到了最低。

(2)Whole-Part (整体一部分) 模式让我们可以通过几个独立的、完备的内部对象组成组件对象。由此形成的组件对内部对象进行了封装, 协调其合作关系,并为其功能提供一一个 公共的接口。客户端不能直接地访问内部的各个部分, 对它们米说只能看到作为整体提供的功能。

(3)Composite(组合)模式为那些由相似类型的对象组成的Whole-Part层级结构定义了一种划分组件对象的方式。这样客户端就可以统一地对待独立的对象和对象的组合体。

(4)Master- Slave(主——从)模式支持容错、并行计算和计算精度。主组件将1:作:分配给组从组件,并根据从组件的计算结果计算出最终结果。

(5)Half-Object plus Protocol(半对象加办议)模式将在多个地址空间使用的逻辑对象组织成两个或多个协作的“半对象”。每个半对象实现这个组件功能的——部分。半对象之间通过同步协议进行协调。

(6)Replicated Component Group(复制组件组)模式通过客户端透明的组件复制来达到容错的目的。复制的组件实现位于不同的网络节点,并组成个组件组。客广端通过一个访问点与组件组进行交互,看上去就像只是一个组件一样。

6.应用控制

​ 为了在网络上部署应用,我们需要把用户界面从应用的核心功能中分离出来。这种分离措施确保我们可以独立地修改和访问用户界面和应用的核心功能。然而在实践中我们怎样才能有效地分离这两个方面呢?我们提供的8个模式就是有关这个主题的。它们可以用于将用户输入转换成具体的服务请求,将服务请求的结果转换成用户输出,以及对应用功能的安全访问。

​ 将用户输入转换成对应用功能的服务请求,执行服务请求并将结果转换成有意义的输出展示给用户并不是件容易的事情。如果用户界面和功能还是分离的,要做到这些就更麻烦了。之所以要分离用户界面和功能,目的往往是为了可以独立地升级用户界面和应用功能,简化底层软件和硬件技术的修改,使得应用可以分布式部署在异质的平台上。

要把应用的用户界面同其他方面的功能分离开需要考虑以下问题:数据结构解耦,位置解耦,工作流解耦技术解耦,对请求进行显式的协调和控制,安全。我们的模式语言中的8个模式一大部分来自Patterns of Enterprise Application Archiecture–正是用米应对以上问题的。这些模式为我们提供了常见的引入上;述分离控制的方式,有隐式的也有显式的。

(1) Page Controller (页面控制器)模式为基于表单的用户界面中每个表单引入一个清晰的入口点一一页面控制器,它将每个表单发出的服务请求的处理与执行联合起来。

(2) Front Contoller (前端控制器)模式为应用建立一个唯一的入口一前置控制器,它将由用户界面发出的服务请求的处理和执行联合起来。

(3) Application Contoller (应用控制器)模式将用户界面的导航和应用的工作流控制分离开。Application Contrller从应用的用户界面收到服务请求,根据当前的工作流状态确定调用哪项服务功能,然后根据服务的执行情况将相应的视图展示在用户界面上。

(4) Command Processor(命令处理程序)模式将服务请求与服务的执行分离开。Command Processor组件 将请求作为独立的对象进行管理,调度请求的执行,为其提供日志、存储、撇销/重做等附加功能。

(5) Template View (模板视图)模式为每个视图引入一个Template View组件,它可以使用某种特定的用户界面技术将应用数据或者其他信息用一种预先设定的视图格式展现出来。

(6) Transform View (转换视图)模式引入了一个Transform View组件,它可以将为响应特定的用户请求而从应用接收到的数据转换成数据上的具体视图。

(7) Firewall Proxy (防火墙代理)模式通过引入一个代理 来阻止来自外部的攻击,这个代理可以检查服务请求,发现其中的可疑内容并将其移除。

(8) Authorization (授权)模式会检查客户端的访问权限,确保只有符合指定访问规则的授权客户端才可以访问应用的特定功能。

7.并发

​ 选择什么样的并发架构会对多线程软件的设计和性能产生极大的影响,而对分布式软件的影响尤为明显。然而,还没有一~种并发架构是适合所有的负载情况和平台的。本章所介绍的4种并发模式可以应对多种并发问题一从将异步并发处理与同步并发处理组合起来,到将对共享组件的访问进行同步,同时保证性能和吞吐量的最大化。

分布式系统软件通常能够从并发中获益,尤其是处理从多个客户端同时发出请求的服务器和服务器端软件。同时,人们设计出越来越多的多核CPU和多CPU计算机来运行多控制线程,以弥补相对于摩尔定律的差距。因此,进程和线程管理机制成了分布式系统软件开发人员必须精通的知识。

​ 进程是一组资源的集合,比如虚拟内存、I/0句柄、控制线程,它为执行程序指令提供上下文。在硬件保护地址空间(hardware-protected address space)中,每个进程便是-一个保护和资源分配单元。相反,线程是一个独立的指令序列,它以进程作为运行的上下文。线程不仅包含指令的指针,同时还包括诸如函数激活记( function activation records,即调用栈)、寄存器组以及线程专属(thread-specifc)的数据等资源。 一个线程是一个执行单元, 它属于某个进程,并且与进程中其他的线程共享地址空间。促使分布式系统软件使用多进程和多线程的原因是多方面的,包括下面这些:

通过使用现代硬件和软件平台的进程并发能力透明地提高性能。

允许程序员进行交叠计算和在服务处理过程中交互,从而明显地提高性能。

​ 对于交互式——比如包含用户界面的软件可以缩短感知响应时间,因为不同的线程

执行不同的服务处理任务,用户可以在某些任务阻塞的时候做其他的工作。

允许多个服务处理任务独立运行,采用同步的编程抽象一比如 双向方法调用,以及阻塞I/0和锁操作一从而简化应用设计。

​ 然而,编写高效、可预料、可缩放而且健壮的并发软件是相当困难的。高效的并发编仅仅是把独立的组件、对象或者服务用各自的控制线程启动起来, 然后就可以撒手不管了。原因包括以下几点:

软件的多样性。既然不同类型的分布式系统软件的结构和行为特点各不相同,所以也就不存在放之四海皆适用的并发模型。例如,有些软件混合使用异步和同步服务处理,有些软件则由事件驱动,还有的软件必须处理不同优先级的服务请求。因此,每个类型的软件所要求的并发模型都可能有所不同,以便为用户提供有质量保证的服务,同时为开发人员提供合适的编程模型。

多线程成本。并发软件的设计者必须清楚多线程会引入上下文切换、同步和在CPU缓存间移动数据的开销。轻率地使用线程机制很可能会减少从并发中获得的好处,甚至得不偿失。因此,设计并发软件时应该尽量将应用多线程的开销降到最低。

可移植性。已有的软件开发方法、工具和操作系统平台的局限也会给并发编程带来额外的复杂性。例如,现代硬件和软件平台的多样性使得开发能够运行在多种操作系统上的并发软件和工具变得异常复杂。

有效地解决这些挑战和复杂性要求开发人员了解并能够正确地运用并发模式。在设计软件的构、子系统和组件的整个过程中,都应该自觉地、认真地理解和应用这些模式。

我们的分布式计算模式语言包含了4个模式, 实践表明这些模式可以帮助我们创建多种并发解央各种设计问题。它们如下所示:

(1) Half- Sync/Half-Async (半同步/半异步)模式对并发系统中的异步和同步服务处理解耦合,以简化编程,而不会过度地影响性能。该模式引入两个相互通信的层,一个用于异步服务处理,另- 一个用于同步服务处理。

(2) LeaderFollowers (领导者/跟随者)模式提供了一个高效的并发模型,在该模型中多个线程轮流使用一套事件源,来检测、分离、分派和处理事件源中出现的服务请求。(3)Active Object (活动对象)模式通过将服务请求和服务执行解耦合来提高并发性,它将对象化的服务请求放到自己的控制线程中,并简化了对它们的访问。

(4)Monitor Object(监控对象)模式通过同步并发的方法来保证同一时刻只有一个方法在运行。它允许一个对象的多个方法以协作的方式来确定他们的执行顺序表。

8.同步

​ 划分任务并在不同的线程上执行,这可不是并发的全部含义。当对象在多个线程中共享时,对其方法的使用会存在线程安全的问题,给出了9种模式以解决同步问题或减少状态的变化从而降低同步方面的需求。

​ 并发编程(Concurrent Programming)比顺序编程(Sequential Programming)因难的原因之一在于它对共享资源的访问需要同步。并行运行的线程可能会访问到同一个对象。有的方法需要修改共享对象的内部状态,如果不进行适当的保护,从不同的线程调用该方法时就可能破坏这个状态。为了避免这个问题,那些不应当同时访问同一对象状态的代码应当被同步到一个临界区(Citical Section)中。临界区是满足下面规则的指令序列:如果某一个线程或进程在临界区中执行,则任何其他线程或进程都不能在同一临界区中执行。

​ 在面向对象编程中保护临界区的通用方法是将类或组件与某种类型的锁对象相关联。例如,互斥对象(Mutal Exclusion object,或称互斥体Mutex) 是一种锁类型,它必须在同一线程内在进入和离开临界区时顺序地获取和释放,这样,如果多个线程试图同时获取互斥体,只有一个线程能成功。其他线程必须等到互斥体被释放,这之后等待线程才能再次竞争锁定互斥体。进入和离开临界区时顺序地获取和释放,这样,如果多个线程试图同时获取互斥体,只有一个线程能成功。其他线程必须等到互斥体被释放,这之后等待线程才能再次竞争锁定互斥体。其他类型的锁机制,如文件锁(File Lock)、信号量(Semaphore)和读写锁( Reader-Writer Lock),都运用类似的获取-释放协议。

​ 尽管在线程中使用锁从概念上来看很直观,在实际中用它来编程却并不简单。例如,如果保持线程锁比实际需要的时间长,使得锁定范围( 在获取锁和释放锁之间的语句)比临界区(必须防止并发性访问的语句)大,会降低共享组件的可用性。在过细的粒度上获取和释放锁则会降低组件的性能一获取锁和释放锁的操作并不是免费的。

​ 另一个常见的同步机制是条件变量,它用来协调线程暂时中止自已直到条件表达式包含的线程间共享数据到达期望的状态。条件变量总是与互斥体同时使用,线程必须在检验条件表达式之前获取互斥体,如果条件表达式为假,线程自动将自己挂起在条件变量上并释放互斥体,因此其他线程可以改变共享数据。当一个合作线程改变了这些数据时,它能通知条件变量,从而自动恢复先前挂起在该变量上的线程并再次获取互斥体。

​ 我们对同步的兴趣通常关注于基于锁的编程,特别是怎样高效地使用锁,而不只是充分地使用。正确性、安全性和有效性是推动我们的技术词汇。然而,锁并不是编写线程安全代码的唯一途径。设计软件以减少状态改变的机会能降低执行同步操作的需要。如果多个线程工作在不相交的数据上,它们之间就不需要同步。工作在共享的不变数据上的线程之间同样也不需要同步,因为不会有变化发生。工作在可以原子更新的数据上的线程也能共享状态改变。最后一个方案激发了无锁编程,它是由特定原语操作支持的,例如整数递增或比较并交换(Compare-And-Swap,CAS)操作在给定平台上是原子的而不需要锁定。然而,无锁编程是很精妙而复杂的主题——基于锁的编程专家都很难做对,而无锁编程天才也很难做对,它在我们给出的模式中并不构成-一个关键的主题。

​ 我们分布式运算模式语言中的9个模式能有助于确保线程间和状态间的交互不会产生竞争条件和死锁,同时仍然尽可能保证效率:

​ (1) Guarded Suspension (守护挂起)模式协调客户端对共享对象的透明访问,使其方法只能在特定条件满足的时候执行。

​ (2)Future(未来)模式提供一个虚拟对象,当客户端在其他并发性计算尚未完成的情况下试图访问对象的字段,它会自动将客户端阻塞。

(3)Thread-Safe Interface(线程安全接口)模式可以降低锁定开销并确定组件内方法调用不会因为要再次获取自己持有的非重入锁而导致自死锁。

(4) Double-Checked Locking (双检锁)模式对于临界区代码只需要在第一次遇到时执行而以后不再需要执行的情形下,可以降低竞争和同步开销,而且仍然保证线程安全性。

(5) Strategized Locking (策略锁)模式通过组件参数化允许用户选择最合适的同步机制来完成对组件的临界区的串行化。

(6) Scoped Locking(区域锁)模式确保控制在进入某一范围内时自动获取锁、离开该范围时自动释放锁,而不必关心是从什么路径离开该范围的。

(7) Thread-Specific Storage (线程专属存储)模式允许多个线程使用一一个“逻

辑上全局的”入口点以获取线程内的对象,而不会对每次对象访问引入锁定开销。

(8) CopiedValue(副本值)模式确保值对象通过复制方式在线程间传递。因为值对象不会在多个线程间共享,所以不存在数据竞争的机会,也就不需要同步。

(9) Immutable Value (恒值)模式在构造时设置值对象的内部状态,而且不允许将来改变其状态。Immutable Value可以在并发性程序中共享而不需要同步。

9.对象间的交互

涉及应用架构的问题并不都是像调用另一个组件内对象的方法这样的简单。很多情况下,应用定义了一个可供他人使用的框架,可以是作为扩充,也可以以插件的形式在。封装了交互模型的框架比起仅仅提供简单、被动对象类型的组件,更有可能带有较复杂的对象之间的处理逻辑设计。本章展示了一系列支持对 象间交互的模式,这些对象可以位于应用、框架或产品线的不同组件中。

构建在组件框架上的应用,可以利用框架的执行、资源及其关系管理的特性,同时应用需要遵循框架的办作协议。在这样的应用中,对象之间的协作往往不是简单地在对象之间进行同步方法和服务调用,还要随着函数调用传递参数以及通过返回值收集结果。虽然组件对象之间的协作常常遵循这个简单模型,但即使在顺序编程中,该模型也不会从头到尾一直保持 。

在设计这种交互时,下面一些问题经常会出现,有些非常普遍,有些则仅限于分布式环境中。 (1) 解耦。 在框架、产品线和所有大型长生命周期的系统中, 组件之间常常是松耦合的, 目的是防止不必要的依赖关系,并对它们的独立改进和重用以及与高层服务的组合提供支持。组件之间的松耦合也为它们之间的交互提供了帮助:尽量降低对特定互操作协议和策略以及用于组件之间交互的数据结构的显式依赖。组件提供的行为依赖于其调用者的类型时,同样会对解耦有所要求。通过组件代码内部的条件语句来解决这种问题是可能的,但要避免结构的复杂并更好地支持代码的维护和演化,我们不应该对这样的依赖关系进行硬编码。 (2) 协调一致性。在软件系统中,组件之间可以脱离彼此独立运作,特别是在分布式和并行软件系统中更是如此。但是,有时候会需要一些组件以一致的方式来对其他组件进行协调,例如,避免其他组件内部状态的不一致,或是根据特定的高层协作或集成场景来安排组件的执行顺序。 (3) 通信开销。较之独立系统,分布式系统中组件对象之间的通信可能导致更高的延迟和阻塞。

​ 因为上面这些问题,无论是在开发分布式或并行软件时,还是在创建框架或定义产品线架构时,应用的设计者必须仔细考虑组件对象彼此之间如何协作。在我们的分布式计算模式语言中,有8种模式可以通过引入高效而又灵活、紧凑的对象互操作,来帮助解决这些问题。

​ (1) Observer (观察者)模式通过支持状态变更的单向传播来辅助互操作对象之间的状态同步。当一个组件对象的状态改变时,其Observer 会得到通知。

​ (2) Double Dispatch (双分派)模式可以帮助组织组件对象之间的通信,在该模式中,被调用对象的行为取决于调用者对象的类型。

​ (3) Mediator (中介者)模式封装了组件对象集合互动的方式。Mediator通过避免对象显式地相互引用使其松散耦合,而且可以独立地改变它们之间的交互。

​ (4) Command (命令)模式将一个请求封装为对象, 这使得我们可以把不同的请求作为客户端的参数,并支持可取消操作。

​ (5) Memento (备忘录)支持在不破坏封装性的前提下,捕获-一个组件对象的内部状态,并在该对象之外保存这个状态。

​ (6) ContextObject (上下文对象)模式以组件对 象的形式捕获环境服务和信息,以支持将这些信息传递给其他需要获取执行上下文的服务和插件对象。

​ (7) Data Transfer Object (数据传输对象)模式通过将一组属性打包到简单属性中,并在再次调用中传入和返回,以减少远程组件对象的更新或查询调用的数量。

(8)Message (消息)模式将两个应用组件对象的交换信息封装到一个数据结构中,并且该结构可以通过网络传播。

10.适配与扩展

现代软件的类型多种多样,而客户也是千人千面。有些应用是专门为某一个客户开发的,有些则面对一个相当规模的市场。有些应用虽然只有一个目标客户,但是如果这个客户经常有一些重复的业务,或者其他的客户也在寻找相似的应用,我们就应当仔细地考患如何定义一个通用的基础,并在此基础之上进行进-一步 的开发。尽管同一个软件系统或者组件可以为多个用户提供服务,但是每个用户往往会有自己的独特要求,而且这些要求可能在默认情况下并不支持。比如下面这些。

​ (1) 带外扩展(Out-of band extensions).有时候客户会要求在系统或其组件的控制流中加入额外的算法或者服务。比如将系统与已有的应用或者某种监控或安全服务集成在一起。这种带外扩展经常是与特定用户紧密相关的。

​ (2) 特殊的算法。即使所有的用户要求的服务是一样的, 他们也经常在关键服务上要求采用特殊的算法,或者要求对算法进行裁剪。比如,业务信息系统必须考虑有关的税务和会计政策,而这些随着时间的推移经常会发生变化。同时根据国家、地区的不同,或者使用该系统的公司法定状态的变化,这些规则也会有相应的不同。

​ (3) 服务扩展和约束。客户经常会对系统中的某些服务要求特定的扩展或者约束。比如,有些客户会要求在执行某个组件的服务之前做一些预处理 工作,或者在其后做-些后续处理。有些用户可能只需要组件的一部分服务,所以需要对服务进行限制。相反,有些用户则会要求对某些组件进行扩展,以支持更多的服务。

​ (4) 多平台支持。不同的客户可能会要求在不同的环境中运行我们的系统。所以,系统的组件应该可以移植到不同的操作系统、库、网络和硬件平台上。分布式系统的组件必须考虑在异质环境中的部署:组件可能部署到多个平台,并跨越多个节点。

​ 我们的分布式计算模式语言包括13个支持配置、适应、扩展和升级系统组件的模式。每个模式用来应对本章开头所列出的一种挑战。而且,其范围并不局限于分布式系统,所有的这些模式在一–切有适应性和扩展性要求的软件,或者在一一个较长的时间内需要维护和改进的软件开发过程中都可以应用。

​ (1) Bridge (桥梁)模式将实现和抽象解耦合,它把一一个对象分为抽象和实现两个部分,并使得双方可以独立地变化。

​ (2) Object Adapter (对象适配器)模式将一 个接口转换成客户端要求的另一个接口。它使得本来由于接口不兼容而无法使用的类可以应用于该系统。它使用一个对象来将原有的类进行包装, 从而确保该类对外是经过封装的。

​ (3) Chain of Responsibility (责任链) 模式通过让更 多的对象有机会处理请求,避免将请求的发送者与其接收者耦合在一起。接收对象被串成-一个链,请求沿着该链依次传送直到某个对象对其进行处理。

​ (4) Interpreter (解释器)模式将语法以对象的形式进行建模,为简单的语言定义-一个解释器。它将语法以可执行的方式表现出来,并用Context对象作为执行的参数来携带调用状态。

​ (5) Interceptor (拦截器)模式(260) 允许将与事件有关的处理透明地插入到框架中,当相应的事件出现时自动触发相应的处理流程。

​ (6) Visitor (访问者)模式(261) 主要用于操作包含不同类型的对象元素的结构。这些操作方法可以针对每个具体的类型而不同,调用这些方法不需要修改被访问对象的类型。

(7)Decorator (装饰器)模式支持为对象动态地添加额外的行为。使用Decorator来扩展功能比做子类化更为灵活。

​ (8)C++中的Excutc-Around Object (环绕执行对象)惯用法定义了一个helper 对象,其构造器和析构器分别在一段指令序列之前和之后执行某些动作,来确保正确性或异常安全性,同时可以减少代码重复。

(9)Template Method (模板方法)模式为操作定义了一一个处理流程框架,它为其子类定义了一些步骤。这样子类就可以重新定义算法中的具体步骤的实现,而不会改变算法的结构。

(10)Strategy (策略)模式定义了一族同时变化的操作。每个变化体封装到一个对象中,而所有的变化体共享相同的接口。这样对这些行为对象的使用便可以独立于其变化体的实现。

(11)Null Object (空对象)通过提供一一个默认的“什么都不做”的对象,封装了缺少实际对象的情形。

(12)Wrapper Facade (包装外观)模式通过为非面向对象的API提供-一个简洁的、健壮的、 可移植的、内聚的面向对象的接口,来达到封装函数和数据的目的。

(13)Declarative Component Configuration (声明组件配置)模式使得组件可以指明它们想要以何种方式集成到容器的组件运行环境和容器本身之中,这样容器便可以自动地执行集成。

参考资料

1.茶轴的青春-搭建可自动化构建的微服务框架

2.面向模式的软件架构,卷4:分布式计算的模式语言

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员之光

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值