基于web编程模式.doc_第1页
基于web编程模式.doc_第2页
基于web编程模式.doc_第3页
基于web编程模式.doc_第4页
基于web编程模式.doc_第5页
已阅读5页,还剩4页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

基于.NET的Web应用框架构建模式 来源:作者: 发布时间:2007-11-09 13:14:02 域名注册o 域名惊喜价格 cn域名1元注册 o com域名39.9元 虚拟主机o 主机按月支付,低至19元/月 o 超大流量,可开子站点 VPS主机o 特惠VPS168元/月,4-8M独享带宽保证 o 独立操作系统,无限开站点 简介 本文对应于Web表示模式集群,文章的前半部分重笔墨的描述了MVC模式的架构、设计及其ASP.NET实现,而在更加复杂的系统中,随后提出了Page Controller(页面控制器)和Front Controller(前端控制器)作为MVC实现的补充,最后,简要介绍了Web表示模式集群的另外两个模式:Intercepting Filter(筛选器)和Page Cache(页面缓存)模式。 “体系结构设计者的第一个作品往往比较简练和干净。他知道自己并不了解正在进行的工作,因此他小心谨慎地设计他。在他设计第一个作品时,会进行多次修饰和润色。这些会留到“下一次”使用这第二个系统是他原来设计的最危险的系统一般趋势是,在设计第二个系统时,将会使用在第一个作品中被小心搁置在一边的所有思路和修饰,从而导致设计过了头。” ?Frederick P. Brooks, Jr.发表于1972年的The Mythical Man Month(人月神话)。 Web上建立的第一个系统是简单地链接在一起的静态HTML页面,以便在分散的小组之间共享文件。随着用户的使用量增加,可响应用户输入的动态网页日益普遍。早期的动态页面一般是以通用网关接口(CGI)脚本的形式编写的。这些CGI脚本不仅包含用来确定在响应用户输入时应当显示什么内容的业务逻辑,而且还会生成表示HTML。随着对更复杂逻辑需求的增加,对更丰富、更生动的表示形式的需求也随之增加。这种增加了的复杂性给CGI编程模型带来了挑战。 不久,基于页面的研发手段(如ASP和JSP)出现了。这些新方法允许研发人员将脚本直接嵌入到HTML面中,从而简化了编程模型。当这些嵌入的脚本应用程式变得更复杂时,研发人员希望在页面级别将业务逻辑和表示逻辑分开。为适应这一需求,随之出现了具有帮助器对象和代码隐藏页面策略的标记库。然后,又出现了提供动态设置站点导航和命令调度程式的精细框架,但所有这一切都是以增加复杂性为代价的。假设目前有大量的Web表示可选方案,怎么为你的应用程式选择适当的Web表示设计策略? 是否真的有一个设计策略能够适应所有的情况?非常不幸,在软件设计中,消除过多的冗余和过度的复杂性是个竞争性需求,非常难能够真正做到两者之间的平衡。你能从包含嵌入脚本的简单页面开始设计工作,但非常快业务逻辑就会不断重复出目前各个文件中,从而导致系统难以维护和扩展。通过将该逻辑移到一组协作组件中,能消除冗余,不过这样做会增加解决方案的复杂性。另一方面,你的设计工作能从设计用来提供标记库、动态设置和命令调度程式的框架入手,可是这样虽然能够消除冗余代码,但他会大大增加系统的复杂性,而这通常是不必要的。 而怎么考虑各个方面的需求,提出一个最合适我们应用的Web表示策略呢?这需要在复杂解决方案(支持将来可能发生变化的情形)和简单解决方案(满足目前的需求)之间做出抉择,原则上适当增加成本是可取的,而过多增加成本却是不可取的。那么废话少说,我们就从“简单”开始吧。 MVC(模型?视图?控制) 许多计算机系统的用途都是从数据存储检索数据并将其显示给用户。在用户更改数据之后,系统再将更新内容存储到数据存储中。因为关键的信息流发生在数据存储和用户界面之间,所以你可能倾向于将这两部分绑在一起,以减少编码量并提高应用程式性能。不过,这种看起来自然而然的方法有一些大问题。一个问题是,用户界面的更改往往比数据存储系统的更改频繁得多。将数据和用户界面这两部分耦合在一起带来的另一个问题是,业务应用程式往往会并入远不止数据传输功能的其他业务逻辑。怎么让Web应用程式的用户界面功能实现模块化,以便你能轻松地独立修改各个部分? Model-View-Controller正是这样的模式,他实现功能模块和显示模块的分离,使得应用程式更加可维护,可扩展,可移植和可复用,他最初是Trygve Reenskaug在二十世纪七十年代末为Smalltalk平台研发的框架Fowler03,而发展到目前为止,已形成了一个非常成熟的模式。 MVC解决方案 Model-View-Controller (MVC)模式基于用户输入,将域的建模、显示和操作分为三个独立的类Burbeck92: q 模型。模型用于管理应用程式域的行为和数据,并响应为获取其状态信息(通常来自视图)而发出的请求,还会响应更改状态的指令(通常来自控制器)。 q 视图。视图用于管理信息的显示。 q 控制器。控制器用于解释用户的鼠标和键盘输入,以通知模型和/或视图进行相应的更改。 视图和控制器都依赖于模型。不过,模型既不依赖于视图,也不依赖于控制器。这是分离的主要好处之一。这样的分离允许模型在独立于可视表示功能的情况下建立和测试。在许多胖客户端应用程式中,视图和控制器的分离是次要的,实际上,许多用户界面框架将角色实现为一个对象。另一方面,在Web应用程式中,视图(浏览器)和控制器(处理HTTP请求的服务器端组件)的分离是非常好定义的。 Model-View-Controller是个用于将用户界面逻辑和业务逻辑分离开来的基础设计模式。遗憾的是,此模式的普及导致了许多错误的描述。特别是在不同的上下文中,术语“控制器”已用于意指不同的事物。幸运的是,Web应用程式的出现已帮助消除了一些不明确性,因为视图和控制器的分离是如此明显。 MVC的变型 在Application Programming in Smalltalk-80: How to use Model-View-Controller (MVC) Burbeck92中,Steve Burbeck描述了MVC的两个变型:被动模型和主动模型。 当一个控制器以独占方式操作模型时,将使用被动模型。控制器将修改模型,然后通知视图:模型已更改,应该进行刷新(见图2)。此情况下的模型完全独立于视图和控制器,这意味着模型无法报告其状态更改。HTTP协议是此方案的示例。浏览器没有从服务器获取异步更新的简单方法。浏览器显示视图并对用户输入作出响应,不过他不会检测服务器上的数据更改。仅当用户显式请求刷新时,才会询问服务器是否发生了更改。 当模型更改状态而不涉及控制器时,将使用主动模型。当其他资源正在更改数据并且更改必须反映在视图中时,可能会发生这种情况。以股票报价机的显示为例。你从外部源接收股票数据,并希望当股票数据更改时更新视图(例如,报价机数据区和警告窗口)。因为只有模型检测对其内部状态的更改(在这些更改发生时),所以模型必须通知视图刷新显示。 不过,使用MVC模式的一个目的是使模型独立于视图。如果模型必须将更改通知视图,则会重新带来你希望避免的依赖性。幸运的是,Observer模式Gamma95提供了这样的机制:提醒其他对象注意状态的更改,而不会导致对这些对象的依赖性。各个视图实现Observer接口,并向模型注册。模型将跟踪由订阅更改的所有观察器组成的列表。当模型发生改动时,模型将会遍历所有已注册的观察器,并将更改通知他们。此方法通常称为“发布-订阅”。模型从不必有关所有视图的特定信息。实际上,在需要将模型更改通知控制器的情况下(例如,启用或禁用菜单选项),控制器必须做的全部工作是实现Observer接口并订阅模型更改。对于存在许多视图的情况,定义多个主体是有意义的,其中每个主体都描述了特定类型的模型更改。然后,每个视图都只能订阅和视图有关的更改类型。图3显示了使用Observer的主动MVC的结构,及观察器怎么将模型和直接引用视图隔离开来。 图4说明当模型发生改动时Observer怎么通知视图。可惜的是,在统一建模语言(UML)序列图中,没有好的方法来演示模型和视图的分离,因为该图表示的是对象的实例而不是类和接口。 MVC的ASP.NET实现 为了解释怎么在ASP.NET中实现Model-View-Controller模式,并说明在软件中分离模型、视图和控制器角色的好处,下面的示例将一个没有分离所有三个角色的单页面解决方案重构为分离这三个角色的解决方案。示例应用程式是个带有下拉列表的网页(如栏下图所示),该页面显示了存储在数据库中的记录。 利用Microsoft Visual Studio(r) .NET研发系统的代码隐藏功能,能非常容易地将表示(视图)代码和Model-Controller代码分离开来。每个ASP.NET页都有一种机制,这种机制允许在独立的类中实现从网页调用的方法。该机制是通过Visual Studio .NET提供的,他有许多好处,例如Microsoft IntelliSense(r)技术。当你使用代码隐藏功能来实现网页时,能使用IntelliSense来显示网页后面的代码中所使用的对象的可用方法列表。IntelliSense不适用于.aspx页。和此同时,为了展现Model-Controller的分离,对于数据库操作提取了DatabaseGateway,这样就实现了三者的完整分离。 视图 解决方案 录音 选择录音: 模型 using System; using System.Collections; using System.Data; using System.Data.SqlClient; public class DatabaseGateway public static DataSet GetRecordings() String selectCmd = select * from Recording; SqlConnection myConnection = new SqlConnection( server=(local);database=recordings;Trusted_Connection=yes); SqlDataAdapter myCommand = new SqlDataAdapter(selectCmd, myConnection); DataSet ds = new DataSet(); myCommand.Fill(ds, Recording); return ds; public static DataSet GetTracks(string recordingId) String selectCmd = String.Format( select * from Track where recordingId = 0 order by id, recordingId); SqlConnection myConnection = new SqlConnection( server=(local);database=recordings;Trusted_Connection=yes); SqlDataAdapter myCommand = new SqlDataAdapter(selectCmd, myConnection); DataSet ds = new DataSet(); myCommand.Fill(ds, Track); return ds; 控制 using System; using System.Data; using System.Collections; using System.Web.UI.WebControls; public class Solution : System.Web.UI.Page protected System.Web.UI.WebControls.Button submit; protected System.Web.UI.WebControls.DataGrid MyDataGrid; protected System.Web.UI.WebControls.DropDownList recordingSelect; private void Page_Load(object sender, System.EventArgs e) if(!IsPostBack) DataSet ds = DatabaseGateway.GetRecordings(); recordingSelect.DataSource = ds; recordingSelect.DataTextField = title; recordingSelect.DataValueField = id; recordingSelect.DataBind(); void SubmitBtn_Click(Object sender, EventArgs e) DataSet ds = DatabaseGateway.GetTracks( (string)recordingSelect.SelectedItem.Value); MyDataGrid.DataSource = ds; MyDataGrid.DataBind(); #region Web Form Designer generated code override protected void OnInit(EventArgs e) / / CODEGEN: 此调用是 ASP.NET Web 窗体设计器所必需的。 / InitializeComponent(); base.OnInit(e); / / 设计器支持所必需的方法 - 不要使用代码编辑器修改 / 此方法的内容。 / private void InitializeComponent() this.submit.Click += new System.EventHandler(this.SubmitBtn_Click); this.Load += new System.EventHandler(this.Page_Load); #endregion 以上示例简单的说明了ASP.NET的MVC实现,在实际项目中,商务逻辑远远不止这样,不过上述的代码展现了一个基本的模型,在增加了代码和复杂度的同时也带来了显而易见的好处,如:模块依赖的降低、代码重复的减少、职责和问题的分离、代码的可测试性等等。 到目前你是否决定了使用Model-View-Controller (MVC)模式来将动态Web应用程式的用户界面组件和业务逻辑分隔开来,要构建的应用程式将以动态方式构造网页,不过目前的页面导航都是基于静态导航的形式。 在更加复杂的应用系统中,怎么考虑尽可能避免导航代码的重复,甚至考虑基于可设置的规则来动态确定页面导航,那么Page Controller和Front Controller某种意义来说是对于MVC模式在更加复杂的系统的优化。 中等复杂程度的优化?Page Controller(页面控制器) 使用Page Controller模式接受来自页面请求的输入、调用请求对模型执行的操作及确定应用于结果页面的正确视图。分隔调度逻辑和所有视图相关代码。如果合适,创建用于所有页面控制器的公用基类,以避免代码重复并提高一致性和可测试性。图5显示了页面控制器和模型和视图的关系。 页面控制器可接收页面请求、提取所有相关数据、调用对模型的所有更新及向视图转发请求。而视图又将根据该模型检索要显示的数据。定义独立页面控制器将分隔模型和Web请求细节(例如会话管理,或使用查询字符串或隐藏表单域向页面传递参数)。按照这种基本形式,为Web应用程式中的每个链接创建控制器。控制器因而将变得非常简单,因为每次仅须考虑一个操作。 为每个网页(或操作)创建独立控制器可能会导致大量代码重复。因此应该创建BaseController类以合并验证参数(请参阅图6)等公用函数。每个独立页面控制器都能从BaseController继承此公用功能。除了从公用基类继承之外,还能定义一组帮助器类,控制器能调用这些类来执行公用功能。 大多数情况下,页面控制器取决于基于HTTP的Web请求的具体细节。因此,页面控制器代码通常包含对HTTP头、查询字符串、表单域、多部分表单请求等的引用。因此在Web应用程式框架之外测试控制器代码非常困难。唯一方法是通过模拟HTTP请求和分析结果来测试控制器。这种类型的测试既费时且易出错。因此,要提高可测试性,能将依赖Web的代码和不依赖Web的代码分别放入两个独立类中(请参阅图7),这是Page Controller的变体实现。 Page Controller是大多数动态Web应用程式的默认实现方式,他简单,Web应用框架内置,可扩展性及其研发人员责任的分隔等等好处使其在Web研发得到广泛的应用,不过每页面一控制器、较深的继承树和对于Web框架的依赖等等也是其比较明显的限制。 高度复杂的优化 ?Front Controller(前端控制器) Front Controller通过让单个控制器负责传输所有请求,从而解决了在Page Controller中存在的分散化问题。控制器本身通常分为以下两部分实现:处理程式和命令层次结构(见图8)。 处理程式具有以下两项职责: 1) 检索参数。处理程式接收来自Web服务器的HTTP Post或Get请求,并从请求中检索相关参数。 2) 选择命令。处理程式首先使用请求中的参数选择正确的命令,然后将控制权转移给该命令以便执行处理。 在前端控制器中,所有请求都通过单个(通常是两部件)控制器来传送。控制器的第一个部件是处理程式,第二个部件是Commands(命令)Gof95的层次。命令本身是控制器的一部分,代表控制器触发的特定操作。在执行该操作之后,命令选择要使用哪个视图来呈现页面。通常,构建的此控制器框架使用设置文件将请求映射到操作,因此,他在构建之后便于更改。当然,其缺点在于这种设计固有的复杂程度。 遗漏之后的补充 到目前为止,已完整地展示了Web表示模式中MVC的实现架构,同时在此技术上对于中等复杂和高度复杂的情况提出了Page Controller和Front Controller作为优化的手段,在构建Web表示的应用程式,已给出了相对完整的解决方案,细心的读者是否发现,是不是还少了一点什么?在构建Web应用程式的时候,除了构建一个“良构”的系统(这表目前MVC的分离和系统的可扩展),我们还需要考虑应用程式的安全和性能,因此我们选取了Interceptiing Filter和Page Cache作为Web表示模式的补充内容。 Intercepting Filter(筛选器) 怎么围绕Web页面请求来实现公共的预处理和后处理步骤?这是筛选器需要解决的问题,使用此模式,你创建一串可组合的筛选器,以便在Web页面请求期间实现公共的预处理和后处理任务。 筛选器构成了一系列独立模块,在将页面请求传递到控制器对象之前,这些模块能链接在一起以执行一组公共的处理步骤。因为各个筛选器实现的是完全相同的接口,所以他们彼此之间没有显式依赖性。因此,能在不会影响现有筛选器的情况下添加新的筛选器。你甚至能在部署时添加筛选器,方法是基于设置文件动态地对他们进行实例化。 对各个筛选器的设计应该尽可能让他们不对是否存在其他筛选器作出所有假设。这样能维护可组合性,即添加、删除或重新排列筛选器的能力。此外,某些实现Intercepting Filter模式的框架不会确保筛选器的执行顺序。如果发现多个筛选器之间存在非常强的相互依赖性,最佳采取调用帮助器类的常规方法,因为这样能确保保留筛选器序列中的约束信息。Intercepting Filter的直接实现方式是个筛选器链,这个筛选器链能用来遍历一个由所有筛选器组成的列表。Web请求处理程式在将控制权传递到应用程式逻辑之前将首先执行筛选器链。 当Web服务器收到页面请求时,请求处理程式首先将控制权传递给FilterChain(筛选器链)对象。此对象维护着一个包含所有筛选器的列表,并按顺序调用每个筛选器。FilterChain能从设置文件中读取筛选器顺序,以实现部署时的可组合性。每个筛选器都有机会修改传入请求。例如,他能修改URL,或添加应用程式要使用的头字段。执行完所有筛选器之后,请求处理程式将控制权传递给控制器,后者将执行应用程式功能(见图12)。 因为在处理Web请求时通常需要有截取筛选器,所以大多数Web框架都为应用程式研发人员提供了将截取筛选器挂靠到请求-响应过程中的机制。 Page Cache(页面缓存) 如果动态生成的Web页被频繁请求并且构建时需要耗用大量的系统资源,那么,怎么才能改进这类网页的响应时间?页面缓存通过对

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论