<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    posts - 176, comments - 240, trackbacks - 0, articles - 7

    WebMVC之前世.今生

    Posted on 2008-02-18 22:02 canonical 閱讀(1815) 評論(0)  編輯  收藏 所屬分類: 設計理論
       所謂WebMVC即Model2模型是目前Web開發領域的主流模型,Struts/Struts2框架是其典型實現。在概念層面上,這種程序組織模型是怎樣建立起來的?與其他Web開發模型(如面向對象模型)具有怎樣的聯系? 它未來可能的發展方向在哪里? 結合Witrix開發平臺的具體實踐,基于級列設計理論我們可以看到一條概念發展的脈絡。http://canonical.javaeye.com/blog/33824

       1. 外部視角:原始的servlet規范提供了一個簡單的面向IO的程序響應模型。一次前臺訪問由一個特定的servlet負責響應,它從request中讀取輸入流,在全局session中保持臨時狀態,向response中寫入輸出流。在此基礎上,JSP提供的模板概念翻轉了程序和輸出文本之間的相對地位,簡化了文本輸出過程。至此,這種整體的程序模型基本上只是規范化了外部系統訪問Web服務器的響應模型,并沒有對后臺程序的具體實現制定明確的約束條件。因此在最粗野的后臺實現中,讀取參數,業務處理,生成頁面等處理步驟是糾纏在一起的,很難理解,也很難重用。每一個后臺頁面都是一個不可分析的整體。
    <%
       String paramA 
    = request.getParameter("paramA");
       ResultSet rsA 
    = 
    %>
       result 
    = <%=rsA.getString(0%>
       String paramB 
    = request.getParamter("paramB");
       ResultSet rsB 
    = 
    <%
       rsB.close();
       rsA.close();
       conn.close();
    %>


    2. 自發分離:在復雜的程序實踐中,我們會自發的對業務處理代碼和界面代碼進行一定程度的分離。因為我們可以直觀的感受到這兩種代碼的穩定性并不匹配。例如不同業務處理過程產生的結果都可以用一個html表格來展現,而同一個業務處理過程產生的結果頁面可能經常發生變化。一般我們傾向于將業務代碼寫在頁面上方,而界面代碼寫在頁面下方,并使用一些原始的分解機制,例如include指令。這種分離是隨意的,缺乏形式邊界的。例如我們無法表達被包含的頁面需要哪些參數,也難以避免全局變量名沖突。需要注意的是,分層的一般意義在于各個層面可以獨立發展,它的隱含假定是各層面之間的交互是規范化的,只使用確定的數據結構,按照確定的方式進行交互。例如業務層和界面層通過標準的List/Map等數據結構交互,而不是使用具有無限多種樣式的特殊的數據結構。(在弱類型語言環境中,實體對象的結構和Map是等價的).
    <%
       List header 
    = 
       List dataList 
    = 
    %>
    <%@ include file="/show_table.jsp" %>


       3. 規范分離:JSP所提供的useBean和tag機制,即所謂的Model1模型,是對程序結構分離的一種規范化。業務代碼封裝在java類中,一般業務函數與web環境無關,即不使用request和response對象, 允許單元測試。tag機制可以看作是對include指令的增強,是一種代碼重用機制。tld描述明確了調用tag時的約束關系。調用tag時需要就地指定調用參數,而include頁面所依賴的參數可能是在此前任意地方指定的,是與功能實現分離的。此外tag所使用的參數名是局部對象上的屬性名,從而避免了對全局變量的依賴。很遺憾的是,jsp tag所封裝的仍然是原始的IO模型,對程序結構缺乏精細的定義,在概念層面上只是對文本片段的再加工,難以支撐復雜的控件結構。早期jsp tag無法利用jsp模板本身來構造,無法構成一個層層遞進的概念抽象機制,更是讓這種孱弱的重用模型雪上加霜。在其位卻無能謀其政,這直接造成了整個j2ee前臺界面抽象層的概念缺失,以致很多人認為一種前臺模板重用機制是無用的。在Witrix平臺中所定義的tpl模板語言,充分利用了xml的結構特點,結合編譯期變換技術,成為Witrix平臺中進行結構抽象的基本手段。實際上,xml能夠有效表達的語義比一般人所想象的要多得多。
     <jsp:useBean id="myBiz" class="" />
      
    <% List dataList = myBiz.process(paramA) %>
      
    <ui:Table data="<%= dataList %>" />

      
      4. 框架分離:在Model1模型中,頁面中存在著大量的粘結性代碼,它們負責解析前臺參數,進行類型轉換和數據校驗,定位特定的業務處理類,設置返回結果,控制頁面跳轉等。一種自然的想法是定義一個全局的程序框架,它根據集中的配置文件完成所有的粘結性操作。這也就是所謂面向action的WebMVC模型。這一模型實現了服務器端業務層和界面層在實現上的分離,但是對于外部訪問者而言,它所暴露的仍然是原始的自動機模型:整個網站是一個龐大的自動機,每次訪問都觸發一個action,在action中可能更改自動機的狀態(作為全局狀態容器的session對象或者數據庫)。struts作為面向action框架的先驅,它也很自然的成為了先烈。struts中所引入的FormBean, 鏈接管理等概念已經在實踐中被證明是無益的。一些新興的框架開始回歸到通用的Map結構,直接指定跳轉頁面,或者利用CoC(Convention Over Configuration)缺省映射.
    public class RegisterAction extends Action {
        
    public ActionForward perform (ActionMapping mapping,
                                      ActionForm form,
                                      HttpServletRequest req,
                                      HttpServletResponse res)
    {
        RegisterForm rf 
    = (RegisterForm) form;
        
        
    return mapping.findForward("success");
    }

      
    5. 橫向延展:分層之后必然導向各個層面的獨立發展,我們的視野自然也會擴大到單個頁面之外,看到一個層面上更多元素之間的相互作用.在面向對象語言大行其道的今天,繼承(inheritance)無疑是多數人首先想到的程序結構組織手段.后臺action可以很自然的利用java語言自身的繼承機制,配置文件中也可以定義類似的extends或者parent屬性.但是對于前臺頁面一般卻很少有適用的抽象手段,于是便有人致力于前臺頁面的對象語言化:首先將前臺頁面采用某種對象語言表達,然后再利用對象語言內置的結構抽象機制.放棄界面的可描述性,將其轉化為某種活動對象,在我看來是一種錯誤的方向.而JSF(JavaServerFace)規范卻似乎想在這個方向上越走越遠.JSF早期設計中存在的一個嚴重問題是延續了面向對象語言中的狀態與行為綁定的組織方式.這造成每次訪問后臺頁面都要重建整個Component Tree, 無法實現頁面結構的有效緩存.而Witrix平臺中的tpl模板語言編譯出的結構是無狀態的,可以在多個用戶之間重用.

      6. 相關聚合:對象化首先意味著相關性的局域化,它并不等價于對象語言化. 當面對一個大的集合的時候,最自然的管理手段便是分組聚合:緊密相關的元素被分配到同一分組,相關性被局域化到組內.例如,針對某個業務對象的增刪改查操作可以看作屬于同一分組. struts中的一個最佳實踐是使用DispatchAction, 它根據一個額外的參數將調用請求映射到Action對象的子函數上.例如/book.do?dispatchMethod=add. 從外部看來,這種訪問方式已經超越了原始的servlet響應模型,看起來頗有一些面向對象的樣子,但也僅僅局限于樣子而已.DispatchAction在struts框架中無疑只是一種權宜之計,它與form, navigation等都是不協調的,而且多個子函數之間并不共享任何狀態變量(即不發生內部的相互作用),并不是真正對象化的組織方式.按照結構主義的觀點,整體大于部分之和.當一組函數聚集在一起的時候,它們所催生的一個概念便是整體的表征:this指針.Witrix平臺中的Jsplet框架是一個面向對象的Web框架,其中同屬于一個對象的多個Action響應函數之間可以共享局部的狀態變量(thisObj),而不僅僅是通過全局的session對象來發生無差別的全局關聯.http://canonical.javaeye.com/blog/33873 需要注意的是,thisObj不僅僅聚集了后臺的業務操作,它同時定義了前后臺之間的一個標準狀態共享機制,實現了前后臺之間的聚合.而前臺的add.jsp, view.jsp等頁面也因此通過thisObj產生了狀態關聯,構成頁面分組.為了更加明確的支持前臺頁面分組的概念,Witrix平臺提供了其他一些輔助關聯手段.例如標準頁面中的按鈕操作都集中在std.js中的stdPage對象上,因此只需要一條語句stdPage.mixin(DocflowOps);即可為docflow定制多個頁面上的眾多相關按鈕操作.此外Witrix平臺中定義了標準的url構建手段,它確保在多個頁面間跳轉的時候,所有以$字符為前綴的參數將被自動攜帶.從概念上說這是一種類似于cookie,但卻更加靈活,更加面向應用的狀態保持機制.

      class DaoWebAction extends WebContext{
         IEntityDao entityDao;
         String metaName;

         
    public Object actQuery(){
           
           thisObj.put(
    "pager",pager);
           
    return success();
         }

         
    public Object actExport(){
           Pager pager 
    = (Pager)thisObj.get("pager");
           
           
    return success();
         }
        }


      7. 描述分離:當明確定義了Action所聚集而成的對象結構之后,我們再次回到問題的原點:如何簡化程序基元(對象)的構建?繼承始終是一種可行的手段,但是它要求信息的組織結構是遞進式的,而很多時候我們實際希望的組織方式只是簡單的加和。通過明確定義的meta(元數據),從對象中分離出部分描述信息,在實踐中被證明是一種有效的手段。同樣的后臺事件響應對象(ActionObject),同樣的前臺界面顯示代碼(PageGroup),配合不同的Meta,可以產生完全不同的行為結果, 表達不同的業務需求。http://canonical.javaeye.com/blog/114066 從概念上說,這可以看作是一種模板化過程或者是一種復雜的策略模式 ProductWebObject = DaoWebObject<ProductMeta>。當然限于技術實現的原因,在一般框架實現中,meta并不是通過泛型技術引入到Web對象中的。目前常見的開發實踐中,經常可以看見類似BaseAction<T>, BaseManager<T>的基類,它們多半僅僅是為了自動實現類型檢查。如果結合Annotation技術,則可以超越類型填充,部分達到Meta組合的效果。使用meta的另外一個副作用在于,meta提供了各個層面之間新的信息傳遞手段,它可以維系多個層面之間的共變(covariant)。例如在使用meta的情況下,后臺代碼調用requestVars(dsMeta.getUpdatableFields())得到提交參數,前臺頁面調用forEach dsMeta.getViewableFields()來生成界面. 則新增一個字段的時候,只需要在meta中修改一處,前后臺即可實現同步更新,自動維持前后臺概念的一致性。有趣的是,前后臺在分離之后它們之間的關聯變得更加豐富。

    8. 切面分離: Meta一般用于引入外部的描述信息,很少直接改變對象的行為結構。AOP(Aspect Oriented Programming)概念的出現為程序結構的組織提供了新的技術手段。AOP可以看作是程序結構空間中定位技術和組裝技術的結合,它比繼承機制和模板機制更加靈活,也更加強大。http://canonical.javaeye.com/blog/34941 Witrix平臺中通過類似AOP的BizFlow技術實現對DaoWebAction和前臺界面的行為擴展,它可以在不擴展DaoWebAction類的情況下,增加/修正/減少web事件響應函數,增加/修正/減少前臺界面展現元素。當前臺發送的$bizId參數不同的時候,應用到WebObject上的行為切片也不同,從而可以自然的支持同一業務對象具有多個不同應用場景的情況(例如審核和擬制)。在BizFlow中定義了明確的實體化過程,前臺提交的集合操作將被分解為針對單個實體的操作。例如前臺提交objectEvent=Remove&id=1&id=2,將會調用兩次<action id="Remove-default">操作。注意到AOP定位技術首先要求的就是良好的坐標定義, 實體化明確定義了實體操作邊界,為實體相關切點的構造奠定了基礎。http://canonical.javaeye.com/blog/33784

    9. 背景消除:在Witrix平臺中, (DaoWebAction + StdPageGroup + Meta + BizFlow)構成完整的程序模型,因此一般情況下并不需要繼承DaoWebAction類,也不需要增加新的前臺頁面文件,而只需要在BizFlow文件中對修正部分進行描述即可。在某種程度上DaoWebAction+StdPageGroup所提供的CRUD(CreateReadUpdateDelete)模型成為了默認的背景知識。如果背景信息極少泄漏,則我們可以在較高抽象層次上進行工作,而不再理會原始的構造機制。例如在深度集成hibernate的情況下,很少會有必須使用SQL語句的需求。BizFlow是對實體相關的所有業務操作和所有頁面展現的集中描述,在考慮到背景知識的情況下,它定義了一個完整的自給自足的程序模型。當我們的建模視角轉移到BizFlow模型上時,可以發展出新的程序構造手段。例如BizFlow之間可以定義類似繼承機制的extends算子,可以定義實體狀態驅動的有限自動機,可以定義不同實體之間的鉤稽關系(實體A發生變化的時候自動更新實體B上的相關屬性),也可以定義對Workflow的自然嵌入機制。從表面上看,BizFlow似乎回歸到了前后臺大雜燴的最初場景(甚至更加嚴重,它同時描述了多個相關頁面和多個相關操作),但是在分分合合的模型建立過程中,大量信息被分解到背景模型中,同時發展了各種高級結構抽象機制, 確保了我們注意力的關注點始終是有限的變化部分。而緊致的描述提高了信息密度,簡化了程序構造過程。http://canonical.javaeye.com/blog/126467
      <bizflow extends="docflow"> <!-- 引入docflow模型,包括一系列界面修正和后臺操作 -->
    <biz id="my">
         
    <tpls>
           
    <tpl id="initTpl">
              
    <script src="my_ops.js" ></script>
              
    <script>
                stdPage.mixin(MyOps); // 引入多個頁面上相關按鈕對應的操作
              
    </script>
           
    </tpl>
         
    </tpls>
        
    </biz>
      
    </bizflow>



    主站蜘蛛池模板: 亚洲国产成a人v在线| 麻豆安全免费网址入口| 男女啪啪永久免费观看网站| 无码精品A∨在线观看免费| 77777亚洲午夜久久多喷| 亚洲成A人片在线观看中文 | rh男男车车的车车免费网站| 亚洲A∨无码一区二区三区| 成人毛片免费观看视频| 三年片免费高清版| 中文字幕乱码亚洲精品一区 | 成人激情免费视频| 男女一边桶一边摸一边脱视频免费 | 华人在线精品免费观看| 亚洲另类无码一区二区三区| 亚洲AV午夜成人片| 免费精品国产自产拍观看| 97青青草原国产免费观看| 乱人伦中文视频在线观看免费| av无码免费一区二区三区| 色老头综合免费视频| 亚洲a级在线观看| 亚洲va久久久噜噜噜久久| 国产一级做a爱免费视频| 国产免费一区二区三区| 免费国产成人午夜在线观看| 理论片在线观看免费| jiz zz在亚洲| 337p日本欧洲亚洲大胆色噜噜 | 国产男女猛烈无遮挡免费网站| 精品一区二区三区无码免费视频| 色妞www精品视频免费看| 亚洲人配人种jizz| 亚洲av日韩综合一区在线观看| 亚洲成aⅴ人片久青草影院| 在线免费观看视频你懂的| 国产免费一区二区三区| 69免费视频大片| 日本亚洲欧洲免费天堂午夜看片女人员| 亚洲国产成人精品不卡青青草原| 亚洲AV无码不卡在线观看下载|