第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 表示模式群集。

Chp_03 Web Presentation_Fig01

图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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值