企业解决方案的构建模式
“ 我们发现,目前正常工作的复杂系统总是从以前正常工作的简单系统演变而来的 …… 从头开始设计的复杂系统总是不能正常工作,也无法通过修补来使其正常工作。您必须从正常工作的简单系统开始。”— John Gall 发表于 Systemantics: How Systems Really Work and How They Fail
企业级业务解决方案是公司实现其业务的赌注,它们通常极其复杂,而且性能必须不负众望。它们不仅必须具有高可用性和伸缩性以应对不可预知的使用,而且还必须具有适应性和预见性以适应快速变化的业务要求。
最佳解决方案是那些由一组更小的、简单的、能够可靠且有效地解决简单问题的机制组成的解决方案。在构建更大、更复杂的系统过程中,将这些简单的机制组合在一起,从而形成更大的系统
本指南旨在获取经验丰富的开发人员的知识,并以模式目录的形式呈现这些知识。每种模式都包含一个简单的、经过证实可以有效解决小问题的机制。虽然您可以单独理解和运用每种模式,但您还会经常组合这些模式来构建复杂的系统。
模式对于开发人员和体系结构设计者非常有用,因为它们:
-
记录能够正常工作的简单机制。
-
为开发人员和体系结构设计者提供通用的词汇和分类法。
-
允许以模式组合的方式简明扼要地描述方案。
-
允许重复使用体系结构、设计和实现决策。
本章将介绍模式的概念,并解释模式如何记录简单的和经过证实的机制,最后展示模式集合如何为开发人员和体系结构设计者提供公用语言。为了阐明这些概念,本章运用了真实开发情形中实际模式的简化版本。
![*](http://msdn2.microsoft.com/zh-cn/library/ms998494.3squares%28zh-cn,MSDN.10%29.gif)
本页内容
模式可以记录简单机制
模式描述给定上下文中反复出现的问题,并基于一组指导性影响因素来建议解决方案。解决方案通常是一种简单的机制,是为了解决模式中所标示出的问题而一起工作的两个或多个类、对象、服务、进程、线程、组件或节点之间的协作。
注意:在这些模式中描述的基础机制虽然概念上很简单,但实际上,它们的实现却相当复杂。实现时,必须具备一定的技能和判断能力,才能对常规模式进行取舍,以适应具体的环境。另外,出于介绍的目的,本章所提到的模式已进行了高度的精简,后面几章将更详细地介绍各种实际模式。
考虑下例:
您正在构建一个报价应用程序,其中有一个类负责管理系统中的所有报价。很重要的一点是,所有报价都应与该类的一个(而且只与一个)实例进行交互。如何构造您的设计,以便从该应用程序中只能访问该类的一个实例?
解决该问题最简单的方案就是创建一个具有私用构造函数的 QuoteManager 类,以便任何其他类都不能实例化它。此类包含 QuoteManager 的一个静态实例,并使用名为 GetInstance() 的静态方法返回。此代码大体如下所示:
public class QuoteManager
{
//注意:仅适用于单线程应用程序
private static QuoteManager _Instance = null;
private QuoteManager() {}
public static QuoteManager GetInstance()
{
if (_Instance==null)
{
_Instance = new QuoteManager ();
}
return _Instance;
}
//... QuoteManager 提供的函数
}
您可能已经像其他许多开发人员那样通过类似的方式解决过类似的问题。实际上,注意反复出现的问题并寻求解决方案的模式作者已经屡次发现了这种实现,提取出了通用解决方案并将这种问题-解决方案对称为 Singleton 模式 [Gamma95]。
问题-解决方案对模式
请注意,Singleton 模式不涉及 Quote 或 QuoteManager 类。但其外观有点类似于下面的简化示例。
通过将图 1 中简化的模式示例与 QuoteManager 源代码进行比较,阐明了模式(通用问题-解决方案对)和模式应用程序(针对非常具体的问题的具体解决方案)之间的区别。模式级别的解决方案是多个类之间简单但极其顺畅的协作。模式中的通用协作专门适用于 QuoteManager 类,提供了用来控制报价应用程序中实例化的机制。显然,您可以稍微修改一下某种模式以满足局部的特定要求,所以同一种模式可以应用于无数个应用程序。
所 编写的模式提供了一种记录简单且经过证实的机制的有效方法。模式是以特定格式编写的,这一点对于装载复杂思想的容器非常有用。这些模式在被记载和起名之 前,就早已存在于开发人员的大脑及其代码中。有时,模式作者从实际的实现中发现了这些模式,并对它们进行推广,以便应用于其他应用程序。
虽 然模式作者通常在这些通用模式中提供了实现代码示例,但是一定要了解实现这些模式还有许多其他正确的方法。其中的关键在于了解模式中的指导原则,并根据自 己的具体情形自定义它。例如,如果您熟悉 Singleton 模式,则可能已注意到代码示例是基于 [Gamma95] 实现的。这里使用该实现的原因在于它是最常见的示例,而且在介绍模式时所需的说明最少。但是,针对 C# 语言优化的 Singleton 实现则会有较大的差异;虽然这两种实现存在很大的区别,但是两者均正确。
位于不同级别的模式
模式存在于多个不同的抽象级别中。考虑另一个示例(这次所处的抽象级别比源代码要高一级):
您要设计一个基于 Web 的报价应用程序,其中包含大量业务和表示逻辑,这些逻辑反过来依赖大量平台软件组件来提供适当的执行环境。如何在高级别组织系统以使其在具有灵活、松耦合性的同时仍具有高内聚性?
此 问题的解决方案之一涉及到按一系列层来组织系统,每层包含大致位于同一抽象级别的元素。随后,确定每一层中的依赖性,并确定采用严格还是宽松的分层策略。 接着,决定是打算创建自定义的分层方案,还是采用以前由其他人记录的分层方案。在本例中,假设您决定使用众所周知的分层策略:表示、业务逻辑和数据访问各 占一层。图 2 显示了分层方案的可能外观。
如 果您总是按这种方式设计系统,说明您已经在不依赖于任何广义模式的情况下使用该模式。即便如此,您还可能因多种原因而希望了解支撑这种设计方法的模式。您 可能迫切想知道为何经常以这种方式构建系统,或者可能在寻找更理想的方法来解决此模式不能完全解决的问题。无论是哪种情况,都值得研究一下这里所使用的模 式和机制。
使用层作为高级别组织方法是 Layers(层)模式 [Buschmann96] 中描述的完善模式。图 3 显示了该模式的简化版本。
这个简单的应用程序组织策略有助于解决软件开发中面临的两个挑战:依存关系的管理和对可交换组件的需求。如果在构建应用程序时没有一个考虑周全的依存关系管理策略,会导致组件易损坏且不牢靠,从而导致对它们进行维护、扩展和替代时存在较大的困难,而且成本较高。
Layers 模式中的工作机制比 Singleton 中的工作机制更精细。对于 Layers,首次协作是在设计时发生在类之间,这是由于分层组织将对更改源代码所带来的影响局部化,从而防止所做的更改贯穿到整个系统。第二次协作发生在运行时:某层中相对独立的组件变得可与其他组件交换,再一次使系统其余部分不受影响。
尽管 Layers 模式的通用性足以应用于诸如网络协议、平台软件和虚拟机之类的领域,但是它无法解决企业类业务解决方案中存在的某些特定问题。例如,除通过分解来管理复杂性(由 Layers 解决的基本问题)外,业务解决方案开发人员还需要进行适当组织,以便有效地重复使用业务逻辑并保留与昂贵资源(如数据库)的重要连接。解决此问题的方法之一就是使用 Three-Layered Application(三层应用程序)模式。图 4 显示了该模式的简化说明。
同样,在模式 (Three-Layered Application) 和模式应用程序(报价应用程序分层模型)之间存在区别。模式是有关应用程序组织主题的通用问题-解决方案对,而模式应用程序是通过创建具体的层(每层都满足非常具体的需求)来解决非常具体的问题。
简单优化
请注意,Three-Layered Application 实际上是在 Layers 的基础上进行的简单优化;在 Layers 中确定的上下文、影响因素和解决方案仍适用于 Three-Layered Application,但反之不行。也就是说,Layers 模式约束着 Three-Layered Application 模式,而 Three-Layered Application 模式优化了 Layers 模式。这种模式关系对于复杂性管理非常有用。当您理解某种模式之后,肯定只是了解了初始模式与其优化模式之间的递增区别。另一个示例(这次涉及 Web Service 领域)应该有助于阐明优化的概念:
您为某个发展迅速的成功企业构建了一个报价应用程序。现在,您希望通过向业务合作伙伴公开自己的报价引擎并将其他合作伙伴服务(如配送)集成到该报价应用程序中来扩展该应用程序。您将如何构造自己的业务应用程序以提供和享受服务?
此问题的解决方案之一是通过将其他与服务相关的职责添加到每一层中来扩展 Three-Layered Application。在业务层添加了以下职责:通过 Service Interfaces(服 务接口)向客户应用程序提供一组简化的操作。数据访问层的职责拓宽到了数据库和主机集成之外,以包括与其他服务提供者的通信。将数据访问层中的这个附加功 能封装到服务接口组件中,这些组件负责连接到服务(同步和异步)、管理服务的基本会话状态并向业务流程组件通知与服务相关的重大事件。
Three-Layered Services Application(三层服务应用程序)(图 5)记录了该问题-解决方案对。
将 Three-Layered Services Application 模式应用于报价应用程序示例将形成如下模型。
请注意这些模式之间的关系(请参阅图 7)。Layers 引进了一个用来组织软件应用程序的基本策略。Three-Layered Application 优化了此概念,并将它限制在需要重复使用业务逻辑、灵活部署和高效使用连接的业务系统的范围内。Three-Layered Services Application 又在 Three-Layered Application 的基础上进行了优化,并对设计进行了扩展,以便在提供和使用其来源千差万别的数据和逻辑时,将这些数据和逻辑处理为粒状元素。
向 特定层中添加其他类型的组件并不是管理这种日益增长的复杂性的唯一方法。正如复杂性所证实的那样,设计人员通常在应用程序中创建其他层来承担该职责。例 如,一些设计人员将服务接口移到一个单独的层中。而另外一些设计人员将业务层分隔成域层和应用程序层。在任何情况下,您有时可能会看到某些设计人员在使用 此模式来满足复杂要求时,有时会将这三层扩展到四层、五层或者甚至六层。与之相反,Layers 模式也用在相对简单的客户端-服务器应用程序中(标准情况是两层应用程序)。
当组合在一起时,Layers 的这些变体组 成了模式群集(请参阅图 8),该模式群集直观地表示出了应用程序分层的常见方法。此上下文中涉及的群集仅表示以逻辑方式组合某组相似的模式。群集的概念对于下列操作非常有用:扩 展模式视图以包含整个解决方案;标识出处理解决方案范围内类似问题的模式群集。第 2 章“组织模式”将更详细地讨论群集。
常见词汇
在考虑 Singleton 、 Layers 、 Three-Layered Application 和 Layered Services Application 模式时,您可能已注意到模式还提供了用来沟通软件体系结构和设计思想的强大词汇。了解模式不仅能够就模式所涉及的知识和体验进行沟通,而且还提供了一个唯一的、便于记忆的名称,以便充当评估和描述软件设计选项时的速记法。
例如,在设计应用程序时,开发人员可能会说:“我认为定价引擎应当作为 Singleton 实现并通过 Service Interface 公开。”如果另一个开发人员了解这些模式,那么他或她将非常清楚所讨论的设计的含义。如果开发人员不理解这些模式,那么他或她可以在目录中查看它们并学习相应的机制,甚至有机会一起学习其他模式。
模式有一种自然分类法。如果您了解足够多的模式及其相互关系,则可以开始了解位于不同抽象级别的、多组经过排序的组和类别。例如,Singleton 模式示例位于比 Layers 模式低的抽象级别,但是,Layers 模式包含一组以不同方式进行过优化的相关模式。第 2 章进一步扩展和优化了此分类法。
随着时间的推移,开发人员不断发现和描述新模式,从而拓宽了开发人员在该领域的知识体系。另外,当您开始了解模式和模式之间的关系时,就可以采用模式术语来描述整个解决方案。
解决方案简述
在 本指南中,术语“解决方案”有两种截然不同的含义:其一是表示模式本身的一部分(如某上下文中包含的问题-解决方案对);其二是表示业务解决方案。在使用 “业务解决方案”这一术语时,它是指专用来满足一组特定的功能和操作业务要求的软件密集型系统。软件密集型系统意味着您不只是关心软件,而且还必须将该软 件部署到硬件处理节点以提供整体的技术解决方案。而且,所考虑的软件不仅包括自定义开发的软件,而且包括购买的软件基础结构和平台组件,所有这些都被集成 在了一起。
小结
本章介绍了模式概念,解释了模式如何记录简单且经过证实的机制,并阐明了模式如何为开发人员和体系结构设计者提供公用语言。第 2 章将解释如何组织关于模式的思想以及如何使用模式来简述整个解决方案。