关闭

使用 Microsoft .NET 的企业解决方案模式

1243人阅读 评论(0) 收藏 举报

    使用 Microsoft .NET 的企业解决方案模式
  
  
  
  版本: 1.1.0
  
  序言
  
  欢迎阅读《使用 Microsoft .NET 的企业解决方案模式》。本指南简要介绍了各种模式,并描述一个按照各种视点和关系对它们进行分类的新组织方法,随后,本指南讨论了其中几个视点所涉及的 32 种模式,并解释了如何将它们集成到企业解决方案中。
  
  在构建和生成企业解决方案时,软件设计人员更多地使用了模式来有效地共享重要的体系结构权衡方法和设计决策。Christopher Alexander 在他的 The Timeless Way of Building 一书中首先用模式来描述体系结构和设计;但是,他的模式是针对城市、建筑物和房屋的。不久,软件设计人员认识到模式作为一种共享设计经验的语言所具有的价值。
  
  在过去的十年中,迅速发展的模式社区已经在系统体系结构和软件开发的许多区域发现了模式。本书包含模式社区持续不断的工作所获得的成果,并通过展示如何将模式应用于构建使用 Microsoft® .NET 的软件密集型系统对它进行了扩展。在早期,客户、合作伙伴和内部反馈指出应当用一本书来回顾已建立的模式和 Microsoft 的特有模式。因此,这就是本书的宗旨。
  
  本书包括已建立的、与平台无关的体系结构和设计模式,然后用专门应用于 Microsoft .NET 的实现模式来扩充了这些模式。来自 .NET 开发人员和系统体系结构设计者的早期反馈已经确认模式是共享 .NET 专业知识的宝贵工具。模式为开发人员和体系结构设计者提供一种通用语言,帮助他们在两个原则之间实现了沟通。本书的作者希望能够向您证明模式的有用性,并且希望您为日益发展的 .NET 模式社区做出贡献。在这方面,还有更多的任务需要完成。
  
  
  
  
  本书面向的读者
  
  本书的大多数读者属于以下三类之一:
  
  不熟悉模式的体系结构设计者、设计人员和开发人员
  已经使用模式构建过企业解决方案的体系结构设计者和设计人员
  架构或设计系统基础机构的系统体系结构设计者或系统工程师
  对于第一组中的读者,前两章对于了解为何以及如何使用模式非常重要。这两章对于理解后四章非常重要,后四章构成模式目录。您可能会发现您已经实现了其中的一些模式,而并不知道它们是模式。
  
  第二组中的读者熟悉第 1 章“企业解决方案的构建模式”中的大部分内容。第 2 章“组织模式”介绍了有关 Microsoft 如何组织其模式储存库的新资料。您将在第 3 章到第 7 章中熟悉大多数模式;但是,所提供的实现示例应当能够帮助您将它们应用于 .NET。
  
  最后一组应当阅读前两章,并特别注意第 4 章“部署模式”和第 7 章“性能和可靠性模式”。这几章专门讨论直接应用于基础结构的模式。
  
  
  
  
  本书结构
  
  前言
  
  第 1 章 企业解决方案的构建模式
  介绍了模式的概念,并解释了模式如何记录经过验证的简单机制,最后讨论了模式集如何为开发人员和体系结构设计者提供通用语言。为了阐释这些概念,本章将实际模式的简化版本应用于实际的开发情形。
  
  第 2 章 组织模式
  解释了模式如何出现在不同的抽象层和各个域之间。本章详细探讨了模式级别,并概括了有助于快速查找相关模式的组织框架。随后,这一章阐释了模式如何在不牺牲细节的情况下提供可高效描述复杂解决方案的词汇。
  
  第 3 章到第 7 章提供了 32 种模式的目录,它们组合成群集。每一章都首先描述特定群集中的模式如何相关,然后给出如何使用模式的指导。对于实现模式,代码示例是用 C# 编写的,并且仅用作示例。示例代码并非针对生产环境。
  
  第 3 章 Web 表示模式
  描述了与构造动态 Web 应用程序相关的设计和实现模式。取决于应用程序的大小和复杂程度,必须做出不同的设计取舍。Web 表示模式群集提供了许多模式替代选项,以阐释应用程序及其最终利弊的各种类型。
  
  本章节包括以下部分内容
  
  模型-视图-控制器
  在 ASP.NET 中实现 Model-View-Controller
  页面控制器
  在 ASP.NET 中实现 Page Controller
  前端控制器
  在 ASP.NET 中使用 HTTPHandler 实现 Front Controller
  截取筛选器
  在 ASP.NET 中使用 HTTP 模块实现 Intercepting Filter
  页面缓存
  在 ASP.NET 中使用绝对过期实现 Page Cache
  观察器
  在 .NET 中实现 Observer
  第 4 章 部署模式
  “部署模式”有助于减小应用程序开发小组和系统基础结构小组之间的交流困难,其方法是指导他们如何以最优方式构造可高效满足解决方案要求的应用程序和技术基础结构。模式讨论了多个主题,如按逻辑分层组织应用程序、优化分层以提供和使用服务、按物理层组织硬件以及用部署计划将进程分配给处理器。
  
  本章节包括以下部分内容
  
  分层应用程序
  三层服务应用程序
  分级分布
  三级分布
  部署规划
  第 5 章 分布式系统模式
  介绍与分布式系统和服务模式群集都相关的概念,其中包括基于接口的协作和基于服务的协作之间的区别,以及近链接和远链接的概念。正如此处定义的那样,分布式系统模式强调基于实例的协作和近链接。
  
  本章节包括以下部分内容
  
  代理程序
  使用服务器激活对象通过 .NET Remoting 实现 Broker
  使用客户端激活对象通过 .NET Remoting 实现 Broker
  数据传输对象
  在 .NET 中使用 DataSet 实现 Data Transfer Object
  在 .NET 中使用类型化 DataSet 实现 Data Transfer Object
  Singleton
  在 C# 中实现 Singleton
  第 6 章 服务模式
  先简要回顾第 5 章中介绍的协作概念,然后介绍多个强调应用程序和外部服务之间协作的模式。与分布式系统相比,服务模式主要关注使用基于服务的协作由远链接连在一起的系统。
  
  本章节包括以下部分内容
  
  服务接口
  在 .NET 中实现 Service Interface
  服务网关
  在 .NET 中实现 Service Gateway
  第 7 章 性能和可靠性模式
  讨论了企业解决方案如何必须确保满足不可预知数量的用户的要求,并且通常必须每周工作七天、每天工作 24 小时。尽管可通过多种方法来提高性能和可靠性,但此模式群集主要关注如何组合服务任意数量的应用程序或用户的多个系统,以提高可伸缩性和可用性。
  
  本章节包括以下部分内容
  
  服务器群集
  负载平衡群集
  故障转移群集
  附录 A
  “Pattlet”提供了本指南所提及的模式的列表,但是并不详细讨论它们。这些模式称作 pattlet,以便与该目录中的其余模式区分开来。有关为何使用 pattlet 的详细信息,请参阅第 2 章“组织模式”。
  
  参考书目
  
  
  
  
  文档约定
  
  本指南使用下面的样式约定和术语。
  表 1:样式惯例表 元素 含义
  加粗 字体 对象、类、方法、预定义的函数和事件。
  倾斜 字体 本指南中引用的模式和 pattlet 的名称。第一次出现的新术语也用倾斜字体表示。
  Monospace 字体 代码示例。
  注意 提示注意补充信息。
  
  
  
  社区
  
  本指南中的模式属于 GotDotNet 上的新模式社区。GotDotNet 是在联机协作开发环境中使用工作区的 Microsoft .NET Framework 社区网站,在这种环境中,.NET 开发人员可以在整个项目生命周期以内创建、托管和管理项目。还可以使用这个模式社区张贴问题、提供反馈或连接其他用户以共享想法。
  
  可从以下网址访问模式社区:http://gotdotnet.com/team/architecture/patterns
  
  
  
  
  反馈和支持
  
  本书作者欢迎您就本书内容提供反馈意见。特别是,如果能就下列主题提供任何指导,他们将不胜感激:
  
  本指南中提供的信息对您是否有用?
  本指南中的信息是否按正确的顺序提供?它们的详细程度是否合适?
  其中的章节是否具有可读性?是否有趣?
  总的来说,您如何评价本资料?
  请将您的反馈意见发送到以下电子邮件地址:pnppatfb@microsoft.com。请注意,不能通过该地址获得技术支持;要获得对 Microsoft 产品和技术的支持,请访问 http://support.microsoft.com
  
  此处记录的模式旨在推动企业应用程序的构造和设计。模式是要应用于所面临问题的简单机制,它们通常与其他模式结合使用。它们并不是要插入到应用程序中。示例代码按原样提供,但并不针对生产环境。它们仅用于阐释模式,因此其中不包括额外代码(如异常处理、日志记录、安全性和验证)。尽管本资料已经通过测试并且由行家审核过,但我们并不提供象传统的 Microsoft 产品那样的支持。
  
  
  
  
  致谢
  
  非常感谢以下顾问为我们提供了宝贵的帮助:
  Ward Cunningham, Cunningham & Cunningham, Inc.
  Martin Fowler, ThoughtWorks, Inc.
  Ralph Johnson, University of Illinois at Urbana-Champaign
  Robert C. Martin, Object Mentor
  还要感谢许多帮助我们出版本书的投稿人,特别感谢以下人员:
  Mohammad Al-Sabt, Microsoft Prescriptive Architecture Guidance
  Chris Colleran, Colleran.net, LLC
  Matt Evans, Microsoft Prescriptive Architecture Guidance
  Xiao Guo, ThoughtWorks, Inc.
  Steve Kirk, MSDN
  Rick McUmber, RDA
  Vijay Srinivasan, Satyam Computer Services
  Jonathan Wanagel, Microsoft Prescriptive Architecture Guidance
  最后,感谢以下公司同意参与我们的用户体验测试:
  Atmedica USA, LLC, a MediMedia USA company
  Safeco Insurance Company
  SBI and Company
  ThoughtWorks, Inc.

 

 

    第1章 企业解决方案的构建模式
  
  版本 1.1.0
  
  “我们发现,目前正常工作的复杂系统总是从以前正常工作的简单系统演变而来的……从头开始设计的复杂系统总是不能正常工作,也无法通过修补来使其正常工作。您必须从正常工作的简单系统开始。”— John Gall 发表于 Systemantics: How Systems Really Work and How They Fail
  
  企业级业务解决方案是公司实现其业务的赌注,它们通常极其复杂,而且性能必须不负众望。它们不仅必须具有高可用性和伸缩性以应对不可预知的使用,而且还必须具有适应性和预见性以适应快速变化的业务要求。
  
  最佳解决方案是那些由一组更小的、简单的、能够可靠且有效地解决简单问题的机制组成的解决方案。在构建更大、更复杂的系统过程中,将这些简单的机制组合在一起,从而形成更大的系统。
  
  对这些简单机制的认识来之不易。它通常存在于有经验的开发人员和体系结构设计者的头脑中,并且是他们潜意识中自然带到项目中的重要知识。
  
  本指南旨在获取经验丰富的开发人员的知识,并以模式目录的形式呈现这些知识。每种模式都包含一个简单的、经过证实可以有效解决小问题的机制。虽然您可以单独理解和运用每种模式,但您还会经常组合这些模式来构建复杂的系统。
  
  模式对于开发人员和体系结构设计者非常有用,因为它们:
  
  记录能够正常工作的简单机制。
  为开发人员和体系结构设计者提供通用的词汇和分类法。
  允许以模式组合的方式简明扼要地描述方案。
  允许重复使用体系结构、设计和实现决策。
  本章将介绍模式的概念,并解释模式如何记录简单的和经过证实的机制,最后展示模式集合如何为开发人员和体系结构设计者提供公用语言。为了阐明这些概念,本章运用了真实开发情形中实际模式的简化版本。
  
  模式可以记录简单机制
  
  模式描述给定上下文中反复出现的问题,并基于一组指导性影响因素来建议解决方案。解决方案通常是一种简单的机制,是为了解决模式中所标示出的问题而一起工作的两个或多个类、对象、服务、进程、线程、组件或节点之间的协作。
  
  
  --------------------------------------------------------------------------------
  注意:在这些模式中描述的基础机制虽然概念上很简单,但实际上,它们的实现却相当复杂。实现时,必须具备一定的技能和判断能力,才能对常规模式进行取舍,以适应具体的环境。另外,出于介绍的目的,本章所提到的模式已进行了高度的精简,后面几章将更详细地介绍各种实际模式。
  --------------------------------------------------------------------------------
  
  考虑下例:
  
  您正在构建一个报价应用程序,其中有一个类负责管理系统中的所有报价。很重要的一点是,所有报价都应与该类的一个(而且只与一个)实例进行交互。如何构造您的设计,以便从该应用程序中只能访问该类的一个实例?
  
  解决该问题最简单的方案就是创建一个具有私用构造函数的 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: 简化的 Singleton 模式
  
  通过将图 1 中简化的模式示例与 QuoteManager 源代码进行比较,阐明了模式(通用问题-解决方案对)和模式应用程序(针对非常具体的问题的具体解决方案)之间的区别。模式级别的解决方案是多个类之间简单但极其顺畅的协作。模式中的通用协作专门适用于 QuoteManager 类,提供了用来控制报价应用程序中实例化的机制。显然,您可以稍微修改一下某种模式以满足局部的特定要求,所以同一种模式可以应用于无数个应用程序。
  
  所编写的模式提供了一种记录简单且经过证实的机制的有效方法。模式是以特定格式编写的,这一点对于装载复杂思想的容器非常有用。这些模式在被记载和起名之前,就早已存在于开发人员的大脑及其代码中。有时,模式作者从实际的实现中发现了这些模式,并对它们进行推广,以便应用于其他应用程序。
  
  虽然模式作者通常在这些通用模式中提供了实现代码示例,但是一定要了解实现这些模式还有许多其他正确的方法。其中的关键在于了解模式中的指导原则,并根据自己的具体情形自定义它。例如,如果您熟悉 Singleton 模式,则可能已注意到代码示例是基于 [Gamma95] 实现的。这里使用该实现的原因在于它是最常见的示例,而且在介绍模式时所需的说明最少。但是,针对 C# 语言优化的 Singleton 实现则会有较大的差异;虽然这两种实现存在很大的区别,但是两者均正确。
  
  位于不同级别的模式
  
  模式存在于多个不同的抽象级别中。考虑另一个示例(这次所处的抽象级别比源代码要高一级):
  
  您要设计一个基于 Web 的报价应用程序,其中包含大量业务和表示逻辑,这些逻辑反过来依赖大量平台软件组件来提供适当的执行环境。如何在高级别组织系统以使其在具有灵活、松耦合性的同时仍具有高内聚性?
  
  此问题的解决方案之一涉及到按一系列层来组织系统,每层包含大致位于同一抽象级别的元素。随后,确定每一层中的依赖性,并确定采用严格还是宽松的分层策略。接着,决定是打算创建自定义的分层方案,还是采用以前由其他人记录的分层方案。在本例中,假设您决定使用众所周知的分层策略:表示、业务逻辑和数据访问各占一层。图 2 显示了分层方案的可能外观。
  
  
  图2. 报价应用程序的层
  
  如果您总是按这种方式设计系统,说明您已经在不依赖于任何广义模式的情况下使用该模式。即便如此,您还可能因多种原因而希望了解支撑这种设计方法的模式。您可能迫切想知道为何经常以这种方式构建系统,或者可能在寻找更理想的方法来解决此模式不能完全解决的问题。无论是哪种情况,都值得研究一下这里所使用的模式和机制。
  
  使用层作为高级别组织方法是 Layers(层)模式 [Buschmann96] 中描述的完善模式。图 3 显示了该模式的简化版本。
  
  
  图3. 简化的 Layers 模式
  
  这个简单的应用程序组织策略有助于解决软件开发中面临的两个挑战:依存关系的管理和对可交换组件的需求。如果在构建应用程序时没有一个考虑周全的依存关系管理策略,会导致组件易损坏且不牢靠,从而导致对它们进行维护、扩展和替代时存在较大的困难,而且成本较高。
  
  Layers 模式中的工作机制比 Singleton 中的工作机制更精细。对于 Layers,首次协作是在设计时发生在类之间,这是由于分层组织将对更改源代码所带来的影响局部化,从而防止所做的更改贯穿到整个系统。第二次协作发生在运行时:某层中相对独立的组件变得可与其他组件交换,再一次使系统其余部分不受影响。
  
  尽管 Layers 模式的通用性足以应用于诸如网络协议、平台软件和虚拟机之类的领域,但是它无法解决企业类业务解决方案中存在的某些特定问题。例如,除通过分解来管理复杂性(由 Layers 解决的基本问题)外,业务解决方案开发人员还需要进行适当组织,以便有效地重复使用业务逻辑并保留与昂贵资源(如数据库)的重要连接。解决此问题的方法之一就是使用 Three-Layered Application(三层应用程序)模式。图 4 显示了该模式的简化说明。
  
  
  
  图4. 简化的 Three-Layered Application
  
  同样,在模式 (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)记录了该问题-解决方案对。
  
  
  
  图5. 简化的 Three-Layered Services Application
  
  将 Three-Layered Services Application 模式应用于报价应用程序示例将形成如下模型。
  
  图6. 应用于报价应用程序的 Three-Layered Services Application
  
  请注意这些模式之间的关系(请参阅图 7)。Layers 引进了一个用来组织软件应用程序的基本策略。Three-Layered Application 优化了此概念,并将它限制在需要重复使用业务逻辑、灵活部署和高效使用连接的业务系统的范围内。Three-Layered Services Application 又在 Three-Layered Application 的基础上进行了优化,并对设计进行了扩展,以便在提供和使用其来源千差万别的数据和逻辑时,将这些数据和逻辑处理为粒状元素。
  
  图7. 相关模式的优
  
  向特定层中添加其他类型的组件并不是管理这种日益增长的复杂性的唯一方法。正如复杂性所证实的那样,设计人员通常在应用程序中创建其他层来承担该职责。例如,一些设计人员将服务接口移到一个单独的层中。而另外一些设计人员将业务层分隔成域层和应用程序层。在任何情况下,您有时可能会看到某些设计人员在使用此模式来满足复杂要求时,有时会将这三层扩展到四层、五层或者甚至六层。与之相反,Layers 模式也用在相对简单的客户端-服务器应用程序中(标准情况是两层应用程序)。
  
  当组合在一起时,Layers 的这些变体组成了模式群集(请参阅图 8),该模式群集直观地表示出了应用程序分层的常见方法。此上下文中涉及的群集仅表示以逻辑方式组合某组相似的模式。群集的概念对于下列操作非常有用:扩展模式视图以包含整个解决方案;标识出处理解决方案范围内类似问题的模式群集。第 2 章“组织模式”将更详细地讨论群集。
  
  
  图8. 模式群集
  
  常见词汇
  
  在考虑 Singleton、Layers、Three-Layered Application 和 Layered Services Application 模式时,您可能已注意到模式还提供了用来沟通软件体系结构和设计思想的强大词汇。了解模式不仅能够就模式所涉及的知识和体验进行沟通,而且还提供了一个唯一的、便于记忆的名称,以便充当评估和描述软件设计选项时的速记法。
  
  例如,在设计应用程序时,开发人员可能会说:“我认为定价引擎应当作为 Singleton 实现并通过 Service Interface 公开。”如果另一个开发人员了解这些模式,那么他或她将非常清楚所讨论的设计的含义。如果开发人员不理解这些模式,那么他或她可以在目录中查看它们并学习相应的机制,甚至有机会一起学习其他模式。
  
  模式有一种自然分类法。如果您了解足够多的模式及其相互关系,则可以开始了解位于不同抽象级别的、多组经过排序的组和类别。例如,Singleton 模式示例位于比 Layers 模式低的抽象级别,但是,Layers 模式包含一组以不同方式进行过优化的相关模式。第 2 章进一步扩展和优化了此分类法。
  
  随着时间的推移,开发人员不断发现和描述新模式,从而拓宽了开发人员在该领域的知识体系。另外,当您开始了解模式和模式之间的关系时,就可以采用模式术语来描述整个解决方案。
  
  解决方案简述
  
  在本指南中,术语“解决方案”有两种截然不同的含义:其一是表示模式本身的一部分(如某上下文中包含的问题-解决方案对);其二是表示业务解决方案。在使用“业务解决方案”这一术语时,它是指专用来满足一组特定的功能和操作业务要求的软件密集型系统。软件密集型系统意味着您不只是关心软件,而且还必须将该软件部署到硬件处理节点以提供整体的技术解决方案。而且,所考虑的软件不仅包括自定义开发的软件,而且包括购买的软件基础结构和平台组件,所有这些都被集成在了一起。
  
  小结
  
  本章介绍了模式概念,解释了模式如何记录简单且经过证实的机制,并阐明了模式如何为开发人员和体系结构设计者提供公用语言。第 2 章将解释如何组织关于模式的思想以及如何使用模式来简述整个解决方案。 
   
   
       第2章 组织模式
  
  版本: 1.1.0
  
  “于是,每种模式既依赖于它所包含的更小的模式,又依赖于包含它的更大的模式。”— Christopher Alexander 发表于The Timeless Way of Building
  
  一项技术领域的革新通常会刺激另一个领域的突破。雷达技术促进了微波炉这一烹调设备的诞生。Internet 本身最初被设计为一种具有预防单点攻击能力的军事通信网络,而现在已转变为世界上最大的知识储存库。同样,模式最初应用于建筑和城镇体系结构,但很快就被软件开发社区采用,并作为一种描述复杂软件系统的方法。
  
  现在,每天都在涌现出大量与软件相关的模式。大量模式引发了一系列新的挑战。开发人员如何标识那些与手头的任务最相关的模式?模式集合是否足以描述整个解决方案?
  
  本章通过示范如何完成下列任务而回答了其中的一些问题:
  
  标识模式之间的关系。
  将模式组合成群集。
  标识位于不同抽象级别的模式。
  将模式应用于一个解决方案的多个方面。
  将模式组织为框架。
  使用模式来简述解决方案。
  模式的模式
  
  面向对象的编程社区之所以如此重视模式,是由于模式能够描述关系。面向对象编程的基本元素是类。但是,如果抛开与构成解决方案的其他类的关系不谈,单个类就没有太大意义。每种模式通常都描述一组类,并强调它们之间的关系和交互。因此,模式将大量类转换成更易于管理的模式集合。
  
  由于在一般应用程序中,可用模式的数量很容易超出类的数量,因此您可能突然发现自己位于模式的海洋。那么,怎样才能了解所有这些模式的含义呢?重申一遍,项目之间的关系似乎是问题的关键。显而易见,一些模式与其他模式紧密相关。例如,有些模式是对另一些模式的优化。Three-Tiered Distribution (三级分布)是Tiered Distribution(分级分布)概念的一个具体应用。Observer (观察器)通常用于实现 Model-View-Controller (模型-视图-控制器)模式的一部分。Page Controller (页面控制器)更加详细地描述了 Model-View-Controller 的控制器部分。在 ASP.NET 中实现 Page Controller 是使用 Microsoft® ASP.NET 对 Page Controller 模式的实现。
  
  要开始按照关系组织模式,请将一组模式设想成小圆(请参阅图 1):
  
  
  图 1. 一组模式
  
  如果您在每对具有某种关系的模式之间绘制一条直线,则可以看到如下所示的图片:
  
  
  图 2. 用直线表示的模式关系
  
  带点随机性的小圆的集合形成了连在一起的模式网。当您查看某种模式时,可以立即标识出与其紧密相关的模式并进行审阅。您还可以标识紧密相关的模式的“邻居”,并查看它们与其他更远的模式存在什么样的关系。
  
  模式群集
  
  使用图表来表示模式之间的关系有助于从一种模式转移到一组相关的模式。但是,它仍不能告诉您该从何处着手。如果您正在构建一个 Web 应用程序,应该首先学习Model-View-Controller 模式,还是应该先查看 Page Cache (页面缓存)?是否还应该查看Broker (代理程序)?
  
  模式群集是一组涉及特定主题区域的模式。例如,您可以从 Web 表示群集开始查找与创建 Web 应用程序前端相关的模式。同样,分布式系统群集包含有助于与远程对象通信的模式。如果将模式集合划分为群集,则可以同时检查一组模式。虽然模式图也显示出了两种模式是相关的,但群集汇总能够更详细地描述如何通过组合不同的模式来构建实际的解决方案。每个群集都为读者提供了指导教程,便于其了解该群集中的所有模式。受 Christopher Alexander 的城镇与构造建筑物世界的启发,您可以将群集与城市邻近地区进行类比。为了将这种类比关系向前推进一点,可以将群集汇总视为当地旅游局提供的交通旅游图。
  
  图 3. 模式群集
  
  最初发布的“使用 Microsoft .NET 的企业解决方案模式 (ESP)”标识出了表 1 中所示的五个群集。
  
  表 1:企业解决方案模式群集
  
  群集 问题
  Web 表示 如何创建动态 Web 应用程序?
  部署 如何将应用程序划分为层,然后将它们部署到多级硬件基础结构上?
  分布式系统 如何与驻留在不同进程或不同计算机中的对象进行通信?
  性能和可靠性 如何创建一个能够满足至关重要的操作要求的系统基础结构?
  服务 如何访问由其他应用程序提供的服务?如何将您的应用程序功能作为服务呈现给其他应用程序?
  
  
  第 3 章到第 7 章将详述这些群集。
  
  不同的抽象级别
  
  将模式划分成群集可使其更便于管理。如果您要构建 Web 应用程序的前端,请从 Web 表示群集着手,然后参加快速教程并查看有哪些其他模式与该群集相关。但请牢记一点,不同的人可能对构建 Web 应用程序的不同方面感兴趣,这取决于他们所扮演的角色或项目所处的阶段。开发人员可能对在 Microsoft .NET Framework 上以最高的效率实现Page Controller 模式最感兴趣,而体系结构设计者可能对决定是使用三级还是四级应用程序体系结构更感兴趣。
  
  因此,抽象级别最适合对模式进行分类,以便不同的用户组可以查找与其感兴趣的领域最匹配的模式。从一般到更具体来划分模式有助于确定应当首先考虑哪些模式。在考虑使用 ASP.NET 实现 Page Cache 模式中描述的复杂的 ASP.NET 缓存指令之前,您可能应该先考虑应用程序应该有多少级。
  
  对模式进行分类的方法之一就是将模式图分成如图 4 所示的三个级别。
  
  图 4. 抽象级别
  
  这种划分方法与某些讲述软件模式的最具影响力的图书中使用的术语基本一致。
  
  体系结构模式
  
  “体系结构模式表示软件系统的基础结构组织架构。它提供一组预定义的子系统、指定它们的职责并包括用来组织它们之间关系的规则和准则。”[Buschmann96]
  
  ESP 遵循 Buschmann 等对结构模式的定义。这些模式描述如何在最高级别构造应用程序。例如,Layered Application (分层应用程序)模式就是一种体系结构模式。
  
  设计模式
  
  “设计模式提供一种用来优化软件系统的子系统或组件或者相互之间的关系的架构。它描述通信组件中经常重复使用的、能够解决特定上下文中的一般设计问题的结构。” [Gamma95]
  
  设计模式提供下一级别的优化,如 Gamma 等的创作性作品中所述。许多图标性模式(如 Model-View-Controller 或Singleton)都位于这一层。
  
  实现模式
  
  模式社区将更详细的、特定于编程语言的模式称为惯用语。此定义适合于软件模式。但是,本指南的适用范围并不局限于软件,它同样适用于软件密集型系统,包括将软件部署到硬件处理节点以提供整体的业务解决方案。因此,ESP 对 Pattern-Oriented Software Architecture (POSA) [Buschmann96] 中给出的惯用语的定义进行了修改,以反映更广泛的范围并将这些模式重新标记为实现模式:
  
  实现模式是特定于某个特殊平台的更低一级的模式。实现模式描述如何使用给定平台的功能实现组件的某些方面或它们之间的关系。
  
  ESP 实现模式阐明了如何使用 .NET Framework 实现设计概念。在某些情况下,该框架中已经包含了大量工作,这更便于开发人员执行任务。
  
  
  --------------------------------------------------------------------------------
  注意:虽然 POSA [Buschmann96] 将惯用语定义为了模式,而且 The Timeless Way of Building [Alexander79] 在 Alexander 的原始模式作品中包括实现模式,但在模式社区的一些成员之间,仍就实现模式是否为真正的模式存在争议。无论如何对它们进行分类,在考虑模式时它们都非常有用,因此将其包含在了本指南中。
  --------------------------------------------------------------------------------
  
  如果将模式集合划分为三个抽象级别,则更便于不同的用户组标识与其感兴趣且擅长的领域相关的模式。生成的模型从高级别组织流出,途经对子系统和组件进行的不断优化,最后使用平台特定的技术实现了这些模式。
  
  视点
  
  虽然抽象级别有助于解决不同用户组的问题,但是它们不能反映出软件解决方案比代码组件包含更多内容这一事实。构建企业解决方案的整体视图包括自定义开发的软件、平台软件、硬件基础结构以及软件到硬件的部署。由于这些区域互相之间存在非常明显的区别,所以有必要将这些模式与该命名相对应。
  
  请牢记,这四个区域描述的是同一个解决方案的不同视点。因此,与优化级别不同的是,这些视点不描述层次结构,而只是提供看待同一事情的四种不同方法。您可以将这些视点比喻为不同类型的地图。一个地区的某张地图可能描绘的是交通网(如公路和高速公路),而同一地区的另一张地图显示的是地形。还可能有另一张地图用来显示州界和县界。每张地图都有其各自的词汇。例如,地形图中的直线表示海拔,而交通图中的直线表示街道。然而,所有地图描述的都是同一个主题:特定的地理区域。
  
  每个视点本身还可以强调不同的抽象级别。因此,ESP 将下列视点描绘为模式图中的垂直薄片:数据库、应用程序和基础结构。应用程序视点和基础结构视点之间通常有一个很大的间隙。概念、抽象和技能集都存在足够大的区别,这样可以保证在应用程序视点和基础结构视点之间插入一个缓冲区,以便帮助在二者之间建立连接。此视点被称作部署视点。
  
  此推理过程将产生如表 2 所示的四个视点。
  
  表 2:企业解决方案模式视点
  
  视点 描述
  数据库 数据库视图描述应用程序的永久层。此视图包括诸如逻辑和物理架构、数据库表、关系和事务处理等内容。
  应用程序 应用程序视图强调解决方案的可执行方面。它包括诸如域模型、类图表、程序集和进程等内容。
  部署 部署视图将应用程序关注点明确映射到基础结构关注点(如将进程映射到处理器)。
  基础结构 基础结构视图包含运行解决方案所必需的所有硬件和网络设备。
  
  
  图5 将这些视点以竖线形式覆盖到模式图和抽象级别上。
  
  图 5. 添加视点
  
  为简单起见,图 5 未显示群集的边界。但是,群集、抽象级别和视点是平行存在的。它们代表访问同一组模式的不同方法。
  
  模式框架
  
  垂直轴上的三个优化级别以及水平轴上的四个视点这一组合形成一个网格状的模式组织图。图 6 显示了这种名为模式框架的排列。
  
  图 6. 模式框架
  
  模式框架作为参考点和导航助手随每个单独的模式描述提供。
  
  约束
  
  模式框架按照各种有意义的子类别组织模式集合。例如,现在可以将重点放在数据库视图的设计模式或应用程序视图的实现模式。
  
  但是,软件采用了各种各样的形式。目前,软件运行在以下几类系统上:嵌入式系统(如起搏器和电信设备)、实时系统(如防锁死刹车系统)或数据仓库系统(旨在分析消费者的购买行为)。如果尝试处理与各种形式的所有软件解决方案相关的模式,将快速扩展任何单一的图书或模式储存库的作用范围。因此,ESP 将模式限制在企业业务解决方案上。因为 ESP 这一术语有些模糊,所以它只是标识模式图中一小组特定的顶级体系结构模式或根模式。该集合中的所有其他模式都遵循下列约束:
  
  联机事务处理 (OLTP)
  面向对象
  分层应用程序
  分级分布系统
  OLTP 系统是用来管理事务处理的数据库子系统。这些子系统确保每个事务的原子性、一致性、独立性及持久性(所谓的 ACID 特性)。实际上,这些应用程序通常处理一个或多个用来维护企业业务状态的关系数据库。换句话说,这些应用程序是用来跟踪客户、订单、帐户等的数据库。通过将 OLTP 标识为模式框架中的顶级约束,ESP 排除了不支持事务处理的联机分析处理 (OLAP) 系统或简单平面文件系统。OLTP 的“联机”特性意味着一旦业务状态发生变化,这些系统将立即读取或更新数据库,而不考虑脱机批处理。
  
  从应用程序视点考虑,模式框架受两种模式的约束:Object-Oriented Application(面向对象的应用程序)和Layered Application.(分层应用程序)。大多数(如果不是全部)应用程序视点模式都依赖面向对象的概念(如封装、多形性和继承)来成功解决影响它们的问题。因此,模式框架只处理面向对象的应用程序,并不特意处理程序上的应用程序。
  
  引人注目的企业应用程序通常包括大量对象和服务,这些对象和服务必须通过协作来提供对业务存在一定价值的东西。为了管理这些协作,必须存在某个高级别系统组织。大多数企业级系统都使用分层方法来管理这种复杂性。因此,模式框架只处理设计为一系列层的应用程序,并特意排除没有或者具有较少内部结构的单一应用程序。
  
  从基础结构视点,该模型被限制在支持跨多个按级排列的服务器分布应用程序的硬件基础结构上。这种分级方法通常用于企业应用程序,这是由于它的启动成本相对较低,而且它支持扩展策略(可通过向基础结构中添加开销不大的服务器以递增方式增加容量)。从模型中排除的是基于以下操作的解决方案:将应用程序部署到单个主机或大型多处理器计算机中。
  
  部署视点关注以下问题:缝合应用程序视点和基础结构视点之间的间隙。因此,它本身没有任何约束,但运行时受应用程序视点和基础结构视点所设置的约束的限制。换句话说,最高级别的部署模式涉及的是将分层应用程序映射到分级分布基础结构中,而不对它本身施加任何其他约束。
  
  如果将这四个高级别约束或根约束视为一个组,将有助于缩小在本指南其余部分中讨论的模式的范围。图 7 显示了位于模块框架顶部的根约束。
  
  图 7. 模式框架的根约束
  
  通过缩小模式框架的范围,可以更详细地阐述具体模式以及这些模式之间的关系。
  
  Pattlets
  
  使用根约束可以将模式的数量减少到易于管理的数量级。然而,详述该网格中的所有模式可能需要大量的工作。如果分开开发所有模式,然后发布“最终模式指南”,将无法获得许多由模式社区实现的价值。随着大家对模式的理解的进步,模式也需要发展。模式不是由单个作者创建的,而是软件开发社区实际应用的结晶。在认识到模式的发展本质之后,本指南的作者已经发布了本文中包括的模式的子集,目的在于听取大家的意见并着手组建一个社区。
  
  但是,如果将模式延缓到稍后一些,会在模式图中留下漏洞,这可能会导致相关的模式突然断开连接。为了使模式图中的关系保持完整,本指南提供了第一版本中未包括的模式(即 Pattlet)。Pattlet 是尚未详细记载的实际模式。Pattlet 描述问题的解决方案,但是不包含对可能影响解决方案的上下文、问题或因素的详细说明。
  
  Pattlet 这一概念对于参考以前的模式作品也非常有用。在过去的十年中,模式社区一直发现并记录软件模式。如果试图重复这些工作,将是非常愚蠢的。而要求读者购买几本其他图书来了解这些模式的上下文的想法也很不明智。因此,本指南在参考有关模式的现有图书中所描述的模式时,包括了一个 Pattlet 模式。Pattlet 还包括对原始作品的参考,以供那些希望更详细查看完整模式的读者参考。
  
  有关所有 Pattlet 的详细列表,请参阅附录 A。
  
  解决方案的模式语言
  
  受到约束的模式框架及其所包含的模式提供了足够多的数据点,以便开始使用模式来描述整个解决方案。实际上,第 1 章中的报价示例可以用模式术语来描述。回忆一下,其要求中指定了一个基于 Web 的报价应用程序。描述解决方案体系结构的用户可能会做如下表述:
  
  首先让我们在抽象的体系结构级别看一下这个报价应用程序。从应用程序视点,报价应用程序是面向对象的应用程序,它在逻辑上构造成Three-Layered Services Application. (三层服务应用程序)。从数据库视点,应用程序是基于 OLTP 处理模型的。从基础结构视点,硬件和网络体系结构是基于 Four-Tiered Distribution(四级分布)的,这要求 Web 服务器功能和应用程序服务器功能具有不同的物理级。最后,从部署视点,小组已经基于复杂的 Web 应用程序创建了一个Deployment Plan (部署规划),以便将组件映射到服务器。
  
  这从所有这四个视点向熟悉参考模式的读者简述了解决方案的体系结构。继续向下移动一个抽象级别,可能会看到作者这样描述系统设计:
  
  从应用程序视点,让我们分别考虑 Three-Layered Services Application(三层服务应用程序)的每一层。
  
  表示层是围绕基于Model-View-Controller (MVC) 的 Web 表示框架构造的。尽管 MVC 将业务层和表示逻辑层分开了,但是每一页都包含大量公共逻辑。为了消除这种冗余,我们使用Page Controller 来呈现公共头和尾注信息并为用户设置友好的显示名称。
  
  业务层包含客户、报价、订单、系列物品和库存域对象。由于开发速度是一个重要要求,因此这些域对象是使用 Table Module(表模块)[Fowler03] 实现的。复杂的 Web 应用程序 Deployment Model (部署模型)要求 Web 级和应用程序级分开。因此,这两级通过一个代理程序进行通信。业务实体充当 Data Transfer Objects [Fowler03],用于封装在这两级之间传送的信息。
  
  数据层使用 Data Table Gateway [Fowler03] 来访问 OLTP 数据库子系统,并使用大量数据访问组件来支持域对象的持久性要求。
  
  从基础结构视点:为了满足业务的操作要求,我们通过添加Load-Balanced Cluster (负载平衡群集)和Failover Cluster(故障转移群集)来基于基本的 Four-Tiered Distribution(四级分布)模型构建。为了满足高级别并发用户的要求,我们在 Web 级中添加了负载平衡功能。为了满足可用性要求,我们在数据库级中添加了群集。
  
  可以继续描述位于同一抽象级别的数据和部署视点。为此,再向下移动一个抽象级别,可能会看到作者这样描述解决方案的实现:
  
  让我们从应用程序视点来查看解决方案。解决方案是使用 Microsoft .NET 技术构建的。表示层基于 ASP.NET 中内置的 Web 表示框架。ASP.NET 使用内置的代码隐藏页功能来简化 Model-View-Controller 的实现。我们使用 ASP.NET 中内置的 Page Controller 机制来实现表示逻辑。业务层中的域对象是 .NET 托管对象。因为表示层和业务层部署在不同的级上,所以我们使用服务器激活对象通过 .NET Remoting 实现 Broker。最后,数据层基于 .NET Framework 中的 ADO.NET 类来提供数据库访问。Table Modules(表模块)和业务实体是使用 ADO.NET 的数据集组件构造的。数据访问组件的其余部分由 Microsoft Application Blocks for .NET 构建块提供。
  
  从基础结构视点:Microsoft SQL Server® 运行在故障转移群集中,用于 OLTP 数据库子系统中。Microsoft 网络负载平衡群集在 Web 服务器之间提供负载平衡。
  
  所有这些会话都经常参考各种模式。最初,这可能有点让人望而却步,但当您了解所使用的模式后,就会认识到即使是一个简短的描述也会让您详细了解系统是如何工作的。请注意,您不必翻阅大量文档或逐步执行无穷无尽的代码行,即可对此有所了解。设想一下在不使用模式的情况下描述解决方案而需涉及到的工作,就不难知道模式所带来的沟通好处。
  
  小结
  
  本章阐释了模式如何在不影响细节的情况下提供可以高效描述复杂解决方案的词汇。模式有效地构成了一种新语言,体系结构设计者和设计人员可以使用它们来交流其想法。
  
  由于在构建企业解决方案时会涉及到大量模式,所以学习这个新语言似乎很难。本指南将各种模式组织成了更小、更紧密相关的模式集,这使您能够根据自己的具体兴趣或项目的阶段,从使用一小组模式开始。
  
  本章介绍了四个有助于浏览模式的机制:
  
  关系。模式之间的关系有助于标识与所用模式紧密相关的模式(如 Page Controller 强调 Model-View-Controller 的控制器方面)。
  群集。群集将属于共同主题范围的模式组合在一起(如 Web 表示)。
  抽象级别。抽象级别使您能够以一种与讨论的详细程度相一致的方式来描述概念(如体系结构会话)。
  视点。视点有助于选择与小组的特定角色相关的词汇(如基础结构小组)。
  这些机制并不是要约束您的想法,而是旨在方便您查看复杂系统。实际上,当您在角色、主题范围和详细程度之间切换时,您也将自然而然地在这些机制之间进行了切换。
  
    第3章 Web 表示模式
  
  版本: 1.1.0
  
  “体系结构设计者的第一个作品往往比较简练和干净。他知道自己并不了解正在进行的工作,因此他小心谨慎地设计它。在他设计第一个作品时,会进行多次修饰和润色。这些会留到“下一次”使用……这第二个系统是他曾经设计的最危险的系统……一般趋势是,在设计第二个系统时,将会使用在第一个作品中被小心搁置在一边的所有思路和修饰,从而导致设计过了头。”— Frederick P. Brooks, Jr. 发表于 1972 年的 The Mythical Man Month
  
  Web 上建立的第一个系统是简单地链接在一起的静态 HTML 页面,以便在分散的小组之间共享文档。随着用户的使用量增加,可响应用户输入的动态网页日益普遍。早期的动态页面一般是以通用网关接口 (CGI) 脚本的形式编写的。这些 CGI 脚本不仅包含用来确定在响应用户输入时应当显示什么内容的业务逻辑,而且还会生成表示 HTML。随着对更复杂逻辑需求的增加,对更丰富、更生动的表示形式的需求也随之增加。这种增加了的复杂性给 CGI 编程模型带来了挑战。
  
  不久,基于页面的开发手段(如 ASP 和 JSP)出现了。这些新方法允许开发人员将脚本直接嵌入到 HTML 面中,从而简化了编程模型。当这些嵌入的脚本应用程序变得更复杂时,开发人员希望在页面级别将业务逻辑与表示逻辑分开。为适应这一要求,随之出现了具有帮助器对象和代码隐藏页面策略的标记库。然后,又出现了提供动态配置站点导航和命令调度程序的精细框架,但所有这一切都是以增加复杂性为代价的。假设现在有大量的 Web 表示可选方案,如何为您的应用程序选择适当的 Web 表示设计策略?
  
  复杂性和冗余
  
  不幸的是,没有一个设计策略能够适合所有情形。这是因为软件设计存在如下竞争性需求:消除过多的冗余和过度的复杂性。
  
  您可以从包含嵌入脚本的简单页面开始设计工作,但很快业务逻辑就会不断重复出现在各个文件中,从而导致系统难以维护和扩展。通过将该逻辑移到一组协作组件中,可以消除冗余,但是这样做会增加解决方案的复杂性。另一方面,您的设计工作可以从设计用来提供标记库、动态配置和命令调度程序的框架入手,可是这样虽然能够消除冗余代码,但它会大大增加系统的复杂性,而这通常是不必要的。
  
  随着复杂性的增加,您的设计意图将会变得越来越模糊,使得其他开发人员更难理解您的系统;这还会导致系统更难维护和扩展,从而增加总拥有成本。如果增加的复杂性是经过认真考虑并且是为了满足当前要求而保留的,则可能是值得的。而有的复杂性可能只是基于某一天会有额外需求这一可能性推测(而不是基于当前的要求)而增加的。这会由于不必要的抽象而影响您的理解并妨碍您为今天提供正常工作的系统,从而使代码混乱。
  
  因此,请重新考虑一下,应该如何通盘考虑这些选项,才能获得适合您的应用程序的 Web 表示设计策略?
  
  首先,一定要了解关键的 Web 应用程序设计问题、可能的解决方案和相关的利弊。本章为开发人员提供了沿着该思路的最佳起点。在该过程中,您将熟悉选项,评估利弊,然后选择符合应用程序要求的最简单的解决方案。在复杂解决方案(支持将来可能发生变化的情形)和简单解决方案(满足目前的要求)之间做出抉择之前,一定要深思熟虑。有时,适当增加成本是可取的,而过多增加成本却是不可取的。
  
  模式概述
  
  此模式群集直接从长期存在的 Model-View-Controller (模型-视图-控制器)(MVC) 开始,自从将业务逻辑和表示逻辑分开以来,该模式已久经时间的考验。虽然此模式不属于新的 [Buschmann96],但是该集合以一种简化形式表示它,可以对其进行定制以便构建业务解决方案(而不是为富客户端构建用户界面框架)。此模式最初是在设计级别编写的,然后映射到了名为 在 ASP.NET 中实现 Model-View-Controller 的平台实现。图 1 显示 Web 表示模式群集。
  
  图1 Web 表示模式群集
  
  在用 Microsoft® ASP.NET 实现 MVC 时,是从一个简单系统示例作为起点的:编写在一个页面上,而且将应用程序逻辑嵌入表示元素中。随着系统越来越复杂,使用了 ASP.NET 的代码隐藏功能来将表示代码(视图)与模型控制器代码分开。这始终能够很好地工作,直至要求迫使您不得不考虑在没有控制器的情况下重复使用模型代码以避免应用程序冗余。此时,需要创建独立模型以抽象化业务逻辑,并使用代码隐藏功能使模型适应视图代码。然后,实现过程结束对该 MVC 方法测试含义的讨论。
  
  迄今为止,使用 Model-View-Controller 模式时一直强调模型和视图;控制器扮演相对次要的角色。实际上,在此模式中工作的控制器是 ASP.NET 中的隐式控制器。它负责感知用户事件(请求和回发),并将这些事件写入适当的系统响应(在本例中,指代码隐藏页中的事件)。
  
  在基于 Web 的动态应用程序中,在每次进行页请求时都会重复许多共同任务,如用户验证、确认、提取请求参数和查找与表示相关的数据库。如果不对这些任务进行管理,则会很快导致不必要的代码重复。因为这些任务与感知用户事件和确定正确的系统响应完全相关,所以用来放置该行为的逻辑位置是在控制器中。
  
  功能更强大的控制
  
  此群集中的下一个模式是 Page Controller(页面控制器),该模式是对 Model-View-Controller 的优化,并且能够满足下一个级别的复杂程度。此模式在页面范围中使用一个控制器,接受来自页请求的输入,针对模型调用请求的操作,然后确定要用作结果页面的正确视图。重复逻辑(如确认)被移到了基本控制器类中。
  
  使用 ASP.NET 实现 Page Controller 用常见的外观示例阐述了 ASP.NET 内置的页面控制器的强大功能。实现过程还结合使用 Template Method(模板方法)[Gamma95] 模式与 Page Controller(页面控制器)模式来定义操作中的算法框架,并将其中的一些步骤交由子类负责。
  
  随着应用程序越来越复杂,页面控制器最终在基类中累积了大量逻辑,此问题通常通过加深页面控制器的继承层次结构来解决。如果应用程序十分复杂,这两种因素都会导致代码难以维护和扩展。同样,某些应用程序需要动态配置导航图,这有可能跨越多个页面控制器。达到这种复杂程度时,应该考虑 Front Controller(前端控制器)。
  
  Front Controller, 是该目录中的下一个模式,它也是对 Model-View-Controller 的优化。在前端控制器中,所有请求都通过单个(通常是两部件)控制器来传送。控制器的第一个部件是处理程序,第二个部件是 Commands(命令)[Gamma95] 的层次。命令本身是控制器的一部分,代表控制器触发的特定操作。在执行该操作之后,命令选择要使用哪个视图来呈现页面。通常,构建的此控制器框架使用配置文件将请求映射到操作,因此,它在构建之后便于更改。当然,其缺点在于这种设计固有的复杂程度。
  
  筛选器和缓存
  
  此群集中的最后两种模式涉及到筛选器和缓存。
  
  Intercepting Filter (截取筛选器)为以下问题提供了解决方案:如何针对 HTTP 请求实现常见的预处理和后处理。在 Intercepting Filter 中,最适合执行非应用程序特定的常见任务,如安全性检查、日志记录、压缩、编码和解码。 Intercepting Filter 通常涉及到执行某个特定任务。在针对 HTTP 请求执行多项任务时,多个筛选器会链接到一起。在 ASP.NET 中使用 HTTP 模块实现 Intercepting Filter 强调可在 ASP.NET 中方便地实现此模式。
  
  Page Cache (页面缓存)通过保留创建成本极高的常用动态网页的副本来满足 Web 应用程序日益增加的可伸缩性和性能要求。在最初创建该页面之后,会发送一份副本以便响应以后的请求。Page Cache 还讨论几个关键的缓存设计因素,如缓存刷新、数据刷新和缓存粒度。在 ASP.NET 中使用绝对过期实现 Page Cache 阐述了 ASP.NET 内置的页面缓存功能。
  
  Web 表示模式
  
  下表列出了 Web 表示模式群集中所包括的模式。这些模式的排列方式为较晚的模式构建在较早的模式之上。这意味着发展方向是从更一般的模式(如 Model-View-Controller)发展到更具体的模式(如 Intercepting Filter)。
  
  表 1:Web 表示模式
  
  模式 问题 关联的实现途径
  Model-View-Controller 如何让 Web 应用程序的用户界面功能实现模块化,以便可以方便地单独修改各个部件? 在 ASP.NET 中实现 Model-View-Controller
  Page Controller 如何以最优方式为中等复杂程度的 Web 应用程序构造控制器,以便在避免代码重复的同时实现重复使用和灵活性? 在 ASP.NET 中实现 Page Controller
  Front Controller 如何以最优方式为非常复杂的 Web 应用程序构造控制器,以便在避免代码重复的同时实现重复使用和灵活性? 在 ASP.NET 中使用 HTTP 处理程序实现 Front Controller
  Intercepting Filter 如何针对网页请求实现常见的预处理和后处理步骤? 在 ASP.NET 中使用 HTTP 模块实现 Intercepting Filter
  Page Cache 如何缩短经常被请求、但在构造时需要占用大量系统资源的动态网页的响应时间? 在 ASP.NET 中使用绝对过期实现 Page Cache
  Observer 一个对象怎样才能向其他对象通知其状态变更,而不必依赖于其他对象的类? 在 .NET 中实现 Observer

 

    Model-View-Controller(模型-视图-控制器)
  
  版本: 1.0.1
  
  上下文
  
  许多计算机系统的用途都是从数据存储检索数据并将其显示给用户。在用户更改数据之后,系统再将更新内容存储到数据存储中。因为关键的信息流发生在数据存储和用户界面之间,所以您可能倾向于将这两部分绑在一起,以减少编码量并提高应用程序性能。但是,这种看起来自然而然的方法有一些大问题。一个问题是,用户界面的更改往往比数据存储系统的更改频繁得多。将数据和用户界面这两部分耦合在一起带来的另一个问题是,业务应用程序往往会并入远不止数据传输功能的其他业务逻辑。
  
  问题
  
  如何让 Web 应用程序的用户界面功能实现模块化,以便您可以轻松地单独修改各个部分?
  
  影响因素
  
  下列影响因素作用于此上下文内的系统,在考虑问题的解决方案时必须协调这些因素:
  
  用户界面逻辑的更改往往比业务逻辑频繁,尤其是在基于 Web 的应用程序中。例如,可能添加新的用户界面页,或者可能完全打乱现有的页面布局。毕竟,基于 Web 的瘦客户端应用程序的优点之一是可以随时更改用户界面,而不必重新分发应用程序。如果将显示代码和业务逻辑组合一起并放在单个对象中,则每次更改用户界面时,都必须修改包含业务逻辑的对象。这很可能引入错误,并需要在对用户界面进行每个极小更改之后都要重新测试所有业务逻辑。
  
  在某些情况下,应用程序以不同的方式显示同一数据。例如,分析员喜欢用电子表格视图显示数据,而管理人员喜欢用饼图显示相同的数据。在一些胖客户端用户界面中,常常用多个视图同时显示相同数据。如果用户在一个视图中更改了数据,则系统必须自动更新该数据的其他所有视图。
  
  设计令人赏心悦目而有效的 HTML 页通常要求采用一套与开发复杂业务逻辑不同的技能。很少有人同时具有这两种技能。因此,将这两部分的开发工作分隔开来是最理想的。
  
  用户界面活动通常由以下两部分组成:显示和更新。显示部分负责从数据源检索数据,并格式化数据以便进行显示。当用户基于该数据执行操作时,更新部分将控制权返回给业务逻辑,以便更新数据。
  
  在 Web 应用程序中,单个页面请求将这两方面的工作组合在一起:与用户所选链接相关联的操作进行的处理,以及目标页面的显示。在许多情况下,目标页可能不与操作直接相关。例如,假设有一个用于显示项目列表的简单 Web 应用程序。在将项目添加到列表或从列表中删除项目之后,用户将返回主列表页。因此,应用程序必须在执行两个有很大差异的命令(添加或删除)之后显示相同页面(列表),而所有这些操作均在同一个 HTTP 请求内进行。
  
  与业务逻辑相比,用户界面代码对设备的依赖性往往更大。如果要将应用程序从基于浏览器的应用程序迁移到个人数字助理 (PDA) 或支持 Web 的手机上,则必须替换很多用户界面代码,而业务逻辑可能不受影响。这两部分的完全分离可以使迁移更快完成,并最大限度地降低将错误引入业务逻辑的风险。
  
  通常,为用户界面创建自动测试比为业务逻辑更难、更耗时。因此,减少直接绑到用户界面中的代码量可提高应用程序的可测试性。
  
  解决方案
  
  Model-View-Controller (MVC) 模式基于用户输入将域的建模、显示和操作分为三个独立的类 [Burbeck92]:
  
  模型。模型用于管理应用程序域的行为和数据,并响应为获取其状态信息(通常来自视图)而发出的请求,还会响应更改状态的指令(通常来自控制器)。
  视图。视图用于管理信息的显示。
  控制器。控制器用于解释用户的鼠标和键盘输入,以通知模型和/或视图进行相应的更改。
  图 1 描述了这三个对象之间的结构关系。
  
  
  
  图 1:MVC 类结构
  
  请务必注意,视图和控制器都依赖于模型。但是,模型既不依赖于视图,也不依赖于控制器。这是分离的主要优点之一。这样的分离允许模型在独立于可视表示功能的情况下建立和测试。在许多胖客户端应用程序中,视图与控制器的分离是次要的,实际上,许多用户界面框架将角色实现为一个对象。另一方面,在 Web 应用程序中,视图(浏览器)与控制器(处理 HTTP 请求的服务器端组件)的分离是很好定义的。
  
  Model-View-Controller 是一个用于将用户界面逻辑与业务逻辑分离开来的基础设计模式。遗憾的是,此模式的普及导致了许多错误的描述。特别是在不同的上下文中,术语"控制器"已经用于意指不同的事物。幸运的是,Web 应用程序的出现已经帮助消除了一些不明确性,因为视图与控制器的分离是如此明显。
  
  变型
  
  在 Application Programming in Smalltalk-80: How to use Model-View-Controller (MVC) [Burbeck92] 中,Steve Burbeck 描述了 MVC 的两个变型:被动模型和主动模型。
  
  当一个控制器以独占方式操作模型时,将使用被动模型。控制器将修改模型,然后通知视图:模型已经更改,应该进行刷新(见图 2)。此情况下的模型完全独立于视图和控制器,这意味着模型无法报告其状态更改。HTTP 协议是此方案的示例。浏览器没有从服务器获取异步更新的简单方法。浏览器显示视图并对用户输入作出响应,但是它不会检测服务器上的数据更改。仅当用户显式请求刷新时,才会询问服务器是否发生了更改。
  
  
  
  图 2:被动模型的行为
  
  当模型更改状态而不涉及控制器时,将使用主动模型。当其他资源正在更改数据并且更改必须反映在视图中时,可能会发生这种情况。以股票报价机的显示为例。您从外部源接收股票数据,并希望当股票数据更改时更新视图(例如,报价机数据区和警告窗口)。因为只有模型检测对其内部状态的更改(在这些更改发生时),所以模型必须通知视图刷新显示。
  
  但是,使用 MVC 模式的一个目的是使模型独立于视图。如果模型必须将更改通知视图,则会重新带来您希望避免的依赖性。幸运的是,Observer 模式 [Gamma95] 提供了这样的机制:提醒其他对象注意状态的更改,而不会导致对这些对象的依赖性。各个视图实现 Observer 接口,并向模型注册。模型将跟踪由订阅更改的所有观察器组成的列表。当模型发生改变时,模型将会遍历所有已注册的观察器,并将更改通知它们。此方法通常称为"发布-订阅"。模型从不需要有关任何视图的特定信息。实际上,在需要将模型更改通知控制器的情况下(例如,启用或禁用菜单选项),控制器必须做的全部工作是实现 Observer 接口并订阅模型更改。对于存在许多视图的情况,定义多个主体是有意义的,其中每个主体都描述了特定类型的模型更改。然后,每个视图都只能订阅与视图有关的更改类型。
  
  图 3 显示了使用 Observer 的主动 MVC 的结构,以及观察器如何将模型与直接引用视图隔离开来。
  
  
  
  图 3:在主动模型中使用观察器将模型与视图分离
  
  图 4 说明当模型发生改变时 Observer 如何通知视图。可惜的是,在统一建模语言 (UML) 序列图中,没有好的方法来演示模型与视图的分离,因为该图表示的是对象的实例而不是类和接口。
  
  
  
  图 4:主动模型的行为
  
  示例
  
  请参阅在 ASP.NET 中实现 Model-View-Controller.
  
  测试考虑事项
  
  在使用 Model-View-Controller 时,可测试性有了极大提高。当组件(尤其是用户界面组件)相互高度依赖时,测试组件变得很困难。这些类型的组件通常需要复杂的设置,只是为了测试简单的功能。更糟的是,在出现错误时,很难确定该问题发生在哪个特定组件上。这就是为什么将任务分离开来是重要的体系结构级别动机。MVC 将存储、显示和更新数据的任务分隔到三个可以分别进行测试的组件中。
  
  除因互相依赖而产生的问题之外,用户界面框架本身是很难测试的。测试用户界面需要冗长乏味的(且易于出错)手动测试,或需要模拟用户操作的测试脚本。这些脚本的开发往往很耗时,而且容易被破坏。MVC 没有消除对用户界面测试的需要,但是,通过将模型与显示逻辑分离,可以允许模型在独立于显示的情况下进行测试,并减少了用户界面的测试步骤数。
  
  结果上下文
  
  围绕 MVC 模式构建显示层具有下列优缺点:
  
  优点
  
  支持多个视图。因为视图与模型分离,而且模型与视图之间没有直接依赖性,所以用户界面可以同时显示同一数据的多个视图。例如,Web 应用程序中的多个页面可以使用同一模型对象。另一个示例是允许用户对页面外观进行更改的 Web 应用程序。这些页面显示来自共享模型的同一数据,但以不同的方式进行显示。
  
  适应更改。用户界面要求的更改往往比业务规则快。用户可能更喜欢新设备(如手机或 PDA)采用另一颜色、字体、屏幕布局和支持级别。因为模型不依赖于视图,所以将新类型的视图添加到系统中通常不会影响模型。因此,更改的作用范围仅限于视图。此模式为其进一步的专门化模式(如 Page Controller 和Front Controller)奠定了基础。
  
  缺点
  
  复杂性。MVC 模式引入了新的间接级别,因此稍微增加了解决方案的复杂性。它还增加了用户界面代码的事件驱动特性,调试用户界面代码会变得更加困难。
  
  频繁更新的成本。将模型与视图分离并不意味着模型的开发人员可以忽略视图的特性。例如,如果模型发生频繁更改,则它可能向视图发出大量更新请求。一些视图(如图形显示)的显示可能需要一定时间。因此,视图可能滞后于更新请求。因此,在对模型进行编码时牢记视图是很重要的。例如,模型可以将多个更新作为单个通知发送到视图。
  
  变体
  
  Document-View 变体可以识别 Model-View-Controller 的所有三个角色,但它把控制器合并到视图中。文档对应于 MVC 中的模型角色。此变体存在于许多现有 GUI 平台中。Document-View 的一个极佳示例是 Microsoft Visual C++® 环境中的 Microsoft® 基础类库 (MFC)。使用此变体时,要考虑到视图与控制器更紧密耦合的影响。
  
  相关模式
  
  有关详细信息,请参阅下列相关模式:
  
  Observer。此模式通常与 MVC 一起提及,因为需要使视图和关联模型保持同步。
  
  Page Controller 和Front Controller 描述 MVC 模式的控制器部分的实现策略。
  
  致谢
  
  Model-View-Controller 最初是 Trygve Reenskaug 在二十世纪七十年代末为 Smalltalk 平台开发的框架 [Fowler03]。您刚才阅读的版本参考了以下著作:
  
  [Burbeck92] Burbeck, Steve. "Application Programming in Smalltalk-80: How to use Model-View-Controller (MVC)."University of Illinois in Urbana-Champaign (UIUC) Smalltalk Archive. Available at: http://st-www.cs.uiuc.edu/users/smarch/st-docs/mvc.html.
  
  [Fowler03] Fowler, Martin. Patterns of Enterprise Application Architecture. Addison-Wesley, 2003.
  
  [Gamma95] Gamma, Helm, Johnson, and Vlissides. Design Patterns: Elements of Reusable Object-Oriented Software. Addison-Wesley, 1995.
  
  

   

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:19837次
    • 积分:234
    • 等级:
    • 排名:千里之外
    • 原创:3篇
    • 转载:10篇
    • 译文:0篇
    • 评论:1条
    最新评论