欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
領(lǐng)悟Web設計模式 (轉載)
 
專(zhuān)欄作品
領(lǐng)悟Web設計模式

領(lǐng)悟Web設計模式
本文發(fā)表在《程序春秋》2004年1期
摘要
本文介紹了在.NET框架下應用Web設計模式改進(jìn)WebForm程序設計的一些基本方法及要點(diǎn)。
關(guān)鍵字
設計模式,ASP.NET,WebForm,MVC,Page Controller,Front Controller,Page Cache
目錄
引言
經(jīng)典的WebForm架構
設計模式
MVC模式下的WebForm
Page Controller模式下的WebForm
Front Controller模式下的WebForm
Page Cache模式下的WebForm
參考資源
下載地址
作者信息
引言
記得微軟剛剛推出ASP.NET時(shí),給人的震撼是開(kāi)發(fā)Web程序不再是編寫(xiě)傳統的網(wǎng)頁(yè),而像是在構造應用程序,因而微軟稱(chēng)之為WebForm。但是兩年后的今天,有相當多的開(kāi)發(fā)人員仍然延用寫(xiě)腳本程序的思路構建一個(gè)又一個(gè)的WebForm,而沒(méi)有發(fā)揮出ASP.NET的優(yōu)勢,就此本文希望通過(guò)實(shí)例能夠啟發(fā)讀者一些新的思路。
由于篇幅有限,本文不可能通過(guò)一個(gè)復雜的Web應用來(lái)向讀者展示結合設計模式的WebForm,但是如果僅僅是一個(gè)小程序的確沒(méi)有使用模式的必要。為了便于理解,希望您能把它想象成是一個(gè)大型系統中的小模塊(如果代碼是大型系統的一部分那么使用模式就變得非常重要)。
在本文的末尾給出了所有源程序的下載地址。
經(jīng)典的WebForm架構
首先來(lái)看一個(gè)簡(jiǎn)單的應用,數據庫設計如下圖,Portal是Subject的父表,通過(guò)portalId進(jìn)行一對多關(guān)聯(lián),程序需要根據portalId顯示不同的Subject列表。
按照我們編寫(xiě)WebForm一般的習慣,首先在頁(yè)面上拖放一個(gè)DropDownList、一個(gè)DataGrid、一個(gè)Button控件:
界面(webForm.aspx):
<form id="webForm" method="post" runat="server"> <asp:DropDownList id="dropDownList" runat="server"></asp:DropDownList> <asp:Button id="button" runat="server" Text="Button"></asp:Button> <asp:DataGrid id="dataGrid" runat="server"></asp:DataGrid> </form> 
然后利用VS.NET代碼隱藏功能編寫(xiě)的核心代碼如下:
后置代碼(webForm.aspx.cs):
//頁(yè)面初始化事件 private void Page_Load(object sender, System.EventArgs e) { if ( ! IsPostBack ) { string SQL_SELECT_PORTAL = "SELECT * FROM PORTAL"; //使用using確保釋放數據庫連接 //連接字符串存放在Web.Config文件中便于修改 using( SqlConnection conn = new SqlConnection( ConfigurationSettings.AppSettings["ConnectionString"] ) ) { SqlDataAdapter dataAdapter = new SqlDataAdapter( SQL_SELECT_PORTAL, conn ); DataSet dataSet = new DataSet(); dataAdapter.Fill( dataSet ); //設置下拉列表的數據源與文本域、值域 dropDownList.DataSource = dataSet; dropDownList.DataTextField = "portalName"; dropDownList.DataValueField = "portalId"; dropDownList.DataBind(); } } } //Button的Click事件 private void button_Click(object sender, System.EventArgs e) { string SQL_SELECT_SUBJECT = "SELECT * FROM SUBJECT WHERE portalId = {0}"; using( SqlConnection conn = new SqlConnection( ConfigurationSettings.AppSettings["ConnectionString"] ) ) { //用下拉列表選擇的值替換掉SQL語(yǔ)句中的待定字符{0} SqlDataAdapter dataAdapter = new SqlDataAdapter( string.Format( SQL_SELECT_SUBJECT, dropDownList.SelectedValue ), conn ); DataSet dataSet = new DataSet(); dataAdapter.Fill( dataSet ); dataGrid.DataSource = dataSet; dataGrid.DataBind(); } } 


執行結果如圖所示,程序將根據下拉列表框選擇的值綁定DataGrid,非常典型的一個(gè)WebForm架構,體現出ASP.NET事件驅動(dòng)的思想,實(shí)現了界面與代碼的分離。但是仔細看看可以從中發(fā)現幾個(gè)問(wèn)題:
對數據庫操作的代碼重復,重復代碼是軟件開(kāi)發(fā)中絕對的“壞味道”,往往由于某些原因當你修改了一處代碼,卻忘記要更改另外一處相同的代碼,從而給程序留下了Bug的隱患。
后置代碼完全依賴(lài)于界面,在WebForm下界面的變化遠遠大于數據存儲結構和訪(fǎng)問(wèn)的變化,當界面改變時(shí)您將不得不修改代碼以適應新的頁(yè)面,有可能將會(huì )重寫(xiě)整個(gè)后置代碼。
后置代碼不僅處理用戶(hù)的輸入而且還負責了數據的處理,如果需求發(fā)生變更,比如需要改變數據的處理方式,那么你將幾乎重寫(xiě)整個(gè)后置代碼。
一個(gè)優(yōu)秀的設計需要每一個(gè)模塊,每一種方法只專(zhuān)注于做一件事,這樣的結構才清晰,易修改,畢竟項目的需求總是在不斷變更的,“唯一不變的就是變化本身”,好的程序一定要為變化作出準備,避免“牽一發(fā)而動(dòng)全身”,所以一定要想辦法解決上述問(wèn)題,下面讓我們來(lái)看看設計模式。
設計模式
設計模式描述了一個(gè)不斷重復出現的問(wèn)題以及對該問(wèn)題的核心解決方案,它是成功的構架、設計及實(shí)施方案,是經(jīng)驗的總結。設計模式的概念最早來(lái)自于西方建筑學(xué),但最成功的案例首推中國古代的“三十六計”。
MVC模式下的WebForm
MVC模式是一個(gè)用于將用戶(hù)界面邏輯與業(yè)務(wù)邏輯分離開(kāi)來(lái)的基礎設計模式,它將數據處理、界面以及用戶(hù)的行為控制分為:Model-View-Controller。
Model:負責當前應用的數據獲取與變更及相關(guān)的業(yè)務(wù)邏輯
View:負責顯示信息
Controller:負責收集轉化用戶(hù)的輸入

View和Controller都依賴(lài)于Model,但是Model既不依賴(lài)于View,也不依賴(lài)于Controller,這是分離的主要優(yōu)點(diǎn)之一,這樣Model可以單獨的建立和測試以便于代碼復用,View和Controller只需要Model提供數據,它們不會(huì )知道、也不會(huì )關(guān)心數據是存儲在SQL Server還是Oracle數據庫中或者別的什么地方。
根據MVC模式的思想,可以將上面例子的后置代碼拆分為Model和Controller,用專(zhuān)門(mén)的一個(gè)類(lèi)來(lái)處理數據,后置代碼作為Controller僅僅負責轉化用戶(hù)的輸入,修改后的代碼為:
Model(SQLHelper.cs):封裝所有對數據庫的操作。
private static string SQL_SELECT_PORTAL = "SELECT * FROM PORTAL"; private static string SQL_SELECT_SUBJECT = "SELECT * FROM SUBJECT WHERE portalId = {0}"; private static string SQL_CONNECTION_STRING = ConfigurationSettings.AppSettings["ConnectionString"]; public static DataSet GetPortal() { return GetDataSet( SQL_SELECT_PORTAL ); } public static DataSet GetSubject( string portalId ) { return GetDataSet( string.Format( SQL_SELECT_SUBJECT, portalId ) ); } public static DataSet GetDataSet( string sql ) { using( SqlConnection conn = new SqlConnection( SQL_CONNECTION_STRING ) ) { SqlDataAdapter dataAdapter = new SqlDataAdapter( sql, conn ); DataSet dataSet = new DataSet(); dataAdapter.Fill( dataSet ); return dataSet; } } Controller(webForm.aspx.cs):負責轉化用戶(hù)的輸入 private void Page_Load(object sender, System.EventArgs e) { if ( ! IsPostBack ) { //調用Model的方法獲得數據源 dropDownList.DataSource = SQLHelper.GetPortal(); dropDownList.DataTextField = "portalName"; dropDownList.DataValueField = "portalId"; dropDownList.DataBind(); } } private void button_Click(object sender, System.EventArgs e) { dataGrid.DataSource = SQLHelper.GetSubject( dropDownList.SelectedValue ); dataGrid.DataBind(); } 
修改后的代碼非常清晰,M-V-C各司其制,對任意模塊的改寫(xiě)都不會(huì )引起其他模塊的變更,類(lèi)似于MFC中Doc/View結構。但是如果相同結構的程序很多,而我們又需要做一些統一的控制,如用戶(hù)身份的判斷,統一的界面風(fēng)格等;或者您還希望Controller與Model分離的更徹底,在Controller中不涉及到Model層的代碼。此時(shí)僅僅靠MVC模式就顯得有點(diǎn)力不從心,那么就請看看下面的Page Controller模式。
Page Controller模式下的WebForm
MVC 模式主要關(guān)注Model與View之間的分離,而對于Controller的關(guān)注較少(在上面的MVC模式中我們僅僅只把Model和Controller分離開(kāi),并未對Controller進(jìn)行更多的處理),但在基于WebForm的應用程序中,View和Controller本來(lái)就是分隔的(顯示是在客戶(hù)端瀏覽器中進(jìn)行),而Controller是服務(wù)器端應用程序;同時(shí)不同用戶(hù)操作可能會(huì )導致不同的Controller策略,應用程序必須根據上一頁(yè)面以及用戶(hù)觸發(fā)的事件來(lái)執行不同的操作;還有大多數WebForm都需要統一的界面風(fēng)格,如果不對此處理將可能產(chǎn)生重復代碼,因此有必要對Controller進(jìn)行更為仔細的劃分。
Page Controller模式在MVC模式的基礎上使用一個(gè)公共的頁(yè)基類(lèi)來(lái)統一處理諸如Http請求,界面風(fēng)格等,如圖:

傳統的WebForm一般繼承自System.Web.UI.Page類(lèi),而Page Controller的實(shí)現思想是所有的WebForm繼承自定義頁(yè)面基類(lèi),如圖:

利用自定義頁(yè)面基類(lèi),我們可以統一的接收頁(yè)面請求、提取所有相關(guān)數據、調用對Model的所有更新以及向View轉發(fā)請求,輕松實(shí)現統一的頁(yè)面風(fēng)格,而由它所派生的Controller的邏輯將變得更簡(jiǎn)單,更具體。
下面看一下Page Controller的具體實(shí)現:
Page Controller(BasePage.cs): public class BasePage : System.Web.UI.Page { private string _title; public string Title//頁(yè)面標題,由子類(lèi)負責指定 { get { return _title; } set { _title = value; } } public DataSet GetPortalDataSource() { return SQLHelper.GetPortal(); } public DataSet GetSubjectDataSource( string portalId ) { return SQLHelper.GetSubject( portalId ); } protected override void Render( HtmlTextWriter writer ) { writer.Write( "<html><head><title>" + Title + "</title></head><body>" );//統一的頁(yè)面頭 base.Render( writer );//子頁(yè)面的輸出 writer.Write( @"<a href=""http://www.asp.net"">ASP.NET</a></body></html>" );//統一的頁(yè)面尾 } } 
現在它封裝了Model的功能,實(shí)現了統一的頁(yè)面標題和頁(yè)尾,子類(lèi)只須直接調用:
修改后的Controller(webForm.aspx.cs):
public class webForm : BasePage//繼承頁(yè)面基類(lèi) { private void Page_Load(object sender, System.EventArgs e) { Title = "Hello, World!";//指定頁(yè)面標題 if ( ! IsPostBack ) { dropDownList.DataSource = GetPortalDataSource();//調用基類(lèi)的方法 dropDownList.DataTextField = "portalName"; dropDownList.DataValueField = "portalId"; dropDownList.DataBind(); } } private void button_Click(object sender, System.EventArgs e) { dataGrid.DataSource = GetSubjectDataSource( dropDownList.SelectedValue ); dataGrid.DataBind(); } } 
從上可以看出BagePage Controller接管了大部分原來(lái)Controller的工作,使Controller變得更簡(jiǎn)單,更容易修改(為了便于講解我沒(méi)有把控件放在BasePage中,但是您完全可以那樣做),但是隨著(zhù)應用復雜度的上升,用戶(hù)需求的變化,我們很容易會(huì )將不同的頁(yè)面類(lèi)型分組成不同的基類(lèi),造成過(guò)深的繼承樹(shù);又例如對于一個(gè)購物車(chē)程序,需要預定義好頁(yè)面路徑;對于向導程序來(lái)說(shuō)路徑是動(dòng)態(tài)的(事先并不知道用戶(hù)的選擇)。
面對以上這些應用來(lái)說(shuō)僅僅使用Page Controller還是不夠的,接下來(lái)再看看Front Controller模式。
Front Controller模式下的WebForm
Page Controller的實(shí)現需要在基類(lèi)中為頁(yè)面的公共部分創(chuàng )建代碼,但是隨著(zhù)時(shí)間的推移,需求會(huì )發(fā)生較大的改變,有時(shí)不得不增加非公用的代碼,這樣基類(lèi)就會(huì )不斷增大,您可能會(huì )創(chuàng )建更深的繼承層次結構以刪除條件邏輯,這樣一來(lái)我們很難對它進(jìn)行重構,因此需要更進(jìn)一步對Page Controller進(jìn)行研究。
Front Controller通過(guò)對所有請求的控制并傳輸解決了在Page Controller中存在的分散化處理的問(wèn)題,它分為Handler和Command樹(shù)兩個(gè)部分,Handler處理所有公共的邏輯,接收HTTP Post或Get請求以及相關(guān)的參數并根據輸入的參數選擇正確的命令對象,然后將控制權傳遞到Command對象,由其完成后面的操作,在這里我們將使用到Command模式。
Command模式通過(guò)將請求本身變成一個(gè)對象可向未指定的應用對象提出請求,這個(gè)對象可被存儲并像其他的對象一樣被傳遞,此模式的關(guān)鍵是一個(gè)抽象的Command類(lèi),它定義了一個(gè)執行操作的接口,最簡(jiǎn)單的形式是一個(gè)抽象的Execute操作,具體的Command子類(lèi)將接收者作為其一個(gè)實(shí)例變量,并實(shí)現Execute操作,指定接收者采取的動(dòng)作,而接收者具有執行該請求所需的具體信息。

因為Front Controller模式要比上面兩個(gè)模式復雜一些,我們再來(lái)看看例子的類(lèi)圖:

關(guān)于Handler的原理請查閱MSDN,在這就不多講了,我們來(lái)看看Front Controller模式的具體實(shí)現:
首先在Web.Config里定義:
<!-- 指定對Dummy開(kāi)頭的aspx文件交由Handler處理 --> <httpHandlers> <add verb="*" path="/WebPatterns/FrontController/Dummy*.aspx" type="WebPatterns.FrontController.Handler,WebPatterns"/> </httpHandlers> <!-- 指定名為FrontControllerMap的頁(yè)面映射塊,交由UrlMap類(lèi)處理,程序將根據key找到對應的url作為最終的執行路徑,您在這可以定義多個(gè)key與url的鍵值對 --> <configSections> <section name="FrontControllerMap" type="WebPatterns.FrontController.UrlMap, WebPatterns"></section> </configSections> <FrontControllerMap> <entries> <entry key="/WebPatterns/FrontController/DummyWebForm.aspx" url="/WebPatterns/FrontController/ActWebForm.aspx" /> 。。。 </entries> </FrontControllerMap> 修改webForm.aspx.cs: private void button_Click( object sender, System.EventArgs e ) { Response.Redirect( "DummyWebForm.aspx?requestParm=" + dropDownList.SelectedValue ); } 當程序執行到這里時(shí)將會(huì )根據Web.Config里的定義觸發(fā)類(lèi)Handler的ProcessRequest事件: Handler.cs: public class Handler : IHttpHandler { public void ProcessRequest( HttpContext context ) { Command command = CommandFactory.Make( context.Request.Params ); command.Execute( context ); } public bool IsReusable { get { return true; } } } 
而它又會(huì )調用類(lèi)CommandFactory的Make方法來(lái)處理接收到的參數并返回一個(gè)Command對象,緊接著(zhù)它又會(huì )調用該Command對象的Execute方法把處理后參數提交到具體處理的頁(yè)面。
public class CommandFactory { public static Command Make( NameValueCollection parms ) { string requestParm = parms["requestParm"]; Command command = null; //根據輸入參數得到不同的Command對象 switch ( requestParm ) { case "1" : command = new FirstPortal(); break; case "2" : command = new SecondPortal(); break; default : command = new FirstPortal(); break; } return command; } } public interface Command { void Execute( HttpContext context ); } public abstract class RedirectCommand : Command { //獲得Web.Config中定義的key和url鍵值對,UrlMap類(lèi)詳見(jiàn)下載包中的代碼 private UrlMap map = UrlMap.SoleInstance; protected abstract void OnExecute( HttpContext context ); public void Execute( HttpContext context ) { OnExecute( context ); //根據key和url鍵值對提交到具體處理的頁(yè)面 string url = String.Format( "{0}?{1}", map.Map[ context.Request.Url.AbsolutePath ], context.Request.Url.Query ); context.Server.Transfer( url ); } } public class FirstPortal : RedirectCommand { protected override void OnExecute( HttpContext context ) { //在輸入參數中加入項portalId以便頁(yè)面處理 context.Items["portalId"] = "1"; } } public class SecondPortal : RedirectCommand { protected override void OnExecute(HttpContext context) { context.Items["portalId"] = "2"; } } 最后在A(yíng)ctWebForm.aspx.cs中: dataGrid.DataSource = GetSubjectDataSource( HttpContext.Current.Items["portalId"].ToString() ); dataGrid.DataBind(); 
上面的例子展示了如何通過(guò)Front Controller集中和處理所有的請求,它使用CommandFactory來(lái)確定要執行的具體操作,無(wú)論執行什么方法和對象,Handler只調用Command對象的Execute方法,您可以在不修改 Handler的情況下添加額外的命令。它允許讓用戶(hù)看不到實(shí)際的頁(yè)面,當用戶(hù)輸入一個(gè)URL時(shí),然后系統將根據web.config文件將它映射到特定的URL,這可以讓程序員有更大的靈活性,還可以獲得Page Controller實(shí)現中所沒(méi)有的一個(gè)間接操作層。
對于相當復雜的Web應用我們才會(huì )采用Front Controller模式,它通常需要將頁(yè)面內置的Controller替換為自定義的Handler,在Front Controllrer模式下我們甚至可以不需要頁(yè)面,不過(guò)由于它本身實(shí)現比較復雜,可能會(huì )給業(yè)務(wù)邏輯的實(shí)現帶來(lái)一些困擾。
以上兩個(gè)Controller模式都是處理比較復雜的WebForm應用,相對于直接處理用戶(hù)輸入的應用來(lái)講復雜度大大提高,性能也必然有所降低,為此我們最后來(lái)看一個(gè)可以大幅度提高程序性能的模式:Page Cache模式。
Page Cache模式下的WebForm
幾乎所有的WebForm面臨的都是訪(fǎng)問(wèn)很頻繁,改動(dòng)卻很少的應用,對WebForm的訪(fǎng)問(wèn)者來(lái)說(shuō)有相當多的內容是重復的,因此我們可以試著(zhù)把WebForm或者某些相同的內容保存在服務(wù)器內存中一段時(shí)間以加快程序的響應速度。
這個(gè)模式實(shí)現起來(lái)很簡(jiǎn)單,只需在頁(yè)面上加入:
<%@ OutputCache Duration="60" VaryByParam="none" %>,
這表示該頁(yè)面會(huì )在60秒以后過(guò)期,也就是說(shuō)在這60秒以?xún)人械膩?lái)訪(fǎng)者看到該頁(yè)面的內容都是一樣的,但是響應速度大大提高,就象靜態(tài)的HTML頁(yè)面一樣。
也許您只是想保存部分的內容而不是想保存整個(gè)頁(yè)面,那么我們回到MVC模式中的SQLHelper.cs,我對它進(jìn)行了少許修改:
public static DataSet GetPortal() { DataSet dataSet; if ( HttpContext.Current.Cache["SELECT_PORTAL_CACHE"] != null ) { //如果數據存在于緩存中則直接取出 dataSet = ( DataSet ) HttpContext.Current.Cache["SELECT_PORTAL_CACHE"]; } else { //否則從數據庫中取出并插入到緩存中,設定絕對過(guò)期時(shí)間為3分鐘 dataSet = GetDataSet( SQL_SELECT_PORTAL ); HttpContext.Current.Cache.Insert( "SELECT_PORTAL_CACHE", dataSet, null, DateTime.Now.AddMinutes( 3 ), TimeSpan.Zero ); } return dataSet; } 
在這里把SELECT_PORTAL_CACHE作為Cache的鍵,把GetDataSet( SQL_SELECT_PORTAL )取出的內容作為Cache的值。這樣除了程序第1次調用時(shí)會(huì )進(jìn)行數據庫操作外,在Cache過(guò)期時(shí)間內都不會(huì )進(jìn)行數據庫操作,同樣大大提高了程序的響應能力。
小結
自從.NET框架引入設計模式以后在很大程度上提高了其在企業(yè)級應用方面的實(shí)力,可以毫不夸張的說(shuō)在企業(yè)級應用方面.NET已經(jīng)趕上了Java的步伐并大有后來(lái)居上之勢,本文通過(guò)一個(gè)實(shí)例的講解向讀者展示了在.NET框架下實(shí)現Web設計模式所需的一些基本知識,希望能起到一點(diǎn)拋磚引玉的作用。
參考資源
下載地址
作者信息
袁劍
Microsoft ASP.NET MVP
2003年12月6日


Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=48637

本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
二級聯(lián)動(dòng) - 莫相會(huì ) - 博客園
基于.NET的Web應用框架構建模式
ADO.NET數據庫
為什么MVC比Webform更好一些?
dropdownlist總是獲取第一個(gè)值
實(shí)現無(wú)刷新DropDownList聯(lián)動(dòng)效果
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久