<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 閱讀(1814) 評論(0)  編輯  收藏 所屬分類: 設(shè)計理論
       所謂WebMVC即Model2模型是目前Web開發(fā)領(lǐng)域的主流模型,Struts/Struts2框架是其典型實現(xiàn)。在概念層面上,這種程序組織模型是怎樣建立起來的?與其他Web開發(fā)模型(如面向?qū)ο竽P?具有怎樣的聯(lián)系? 它未來可能的發(fā)展方向在哪里? 結(jié)合Witrix開發(fā)平臺的具體實踐,基于級列設(shè)計理論我們可以看到一條概念發(fā)展的脈絡(luò)。http://canonical.javaeye.com/blog/33824

       1. 外部視角:原始的servlet規(guī)范提供了一個簡單的面向IO的程序響應(yīng)模型。一次前臺訪問由一個特定的servlet負責響應(yīng),它從request中讀取輸入流,在全局session中保持臨時狀態(tài),向response中寫入輸出流。在此基礎(chǔ)上,JSP提供的模板概念翻轉(zhuǎn)了程序和輸出文本之間的相對地位,簡化了文本輸出過程。至此,這種整體的程序模型基本上只是規(guī)范化了外部系統(tǒng)訪問Web服務(wù)器的響應(yīng)模型,并沒有對后臺程序的具體實現(xiàn)制定明確的約束條件。因此在最粗野的后臺實現(xiàn)中,讀取參數(shù),業(yè)務(wù)處理,生成頁面等處理步驟是糾纏在一起的,很難理解,也很難重用。每一個后臺頁面都是一個不可分析的整體。
    <%
       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. 自發(fā)分離:在復雜的程序?qū)嵺`中,我們會自發(fā)的對業(yè)務(wù)處理代碼和界面代碼進行一定程度的分離。因為我們可以直觀的感受到這兩種代碼的穩(wěn)定性并不匹配。例如不同業(yè)務(wù)處理過程產(chǎn)生的結(jié)果都可以用一個html表格來展現(xiàn),而同一個業(yè)務(wù)處理過程產(chǎn)生的結(jié)果頁面可能經(jīng)常發(fā)生變化。一般我們傾向于將業(yè)務(wù)代碼寫在頁面上方,而界面代碼寫在頁面下方,并使用一些原始的分解機制,例如include指令。這種分離是隨意的,缺乏形式邊界的。例如我們無法表達被包含的頁面需要哪些參數(shù),也難以避免全局變量名沖突。需要注意的是,分層的一般意義在于各個層面可以獨立發(fā)展,它的隱含假定是各層面之間的交互是規(guī)范化的,只使用確定的數(shù)據(jù)結(jié)構(gòu),按照確定的方式進行交互。例如業(yè)務(wù)層和界面層通過標準的List/Map等數(shù)據(jù)結(jié)構(gòu)交互,而不是使用具有無限多種樣式的特殊的數(shù)據(jù)結(jié)構(gòu)。(在弱類型語言環(huán)境中,實體對象的結(jié)構(gòu)和Map是等價的).
    <%
       List header 
    = 
       List dataList 
    = 
    %>
    <%@ include file="/show_table.jsp" %>


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

      
      4. 框架分離:在Model1模型中,頁面中存在著大量的粘結(jié)性代碼,它們負責解析前臺參數(shù),進行類型轉(zhuǎn)換和數(shù)據(jù)校驗,定位特定的業(yè)務(wù)處理類,設(shè)置返回結(jié)果,控制頁面跳轉(zhuǎn)等。一種自然的想法是定義一個全局的程序框架,它根據(jù)集中的配置文件完成所有的粘結(jié)性操作。這也就是所謂面向action的WebMVC模型。這一模型實現(xiàn)了服務(wù)器端業(yè)務(wù)層和界面層在實現(xiàn)上的分離,但是對于外部訪問者而言,它所暴露的仍然是原始的自動機模型:整個網(wǎng)站是一個龐大的自動機,每次訪問都觸發(fā)一個action,在action中可能更改自動機的狀態(tài)(作為全局狀態(tài)容器的session對象或者數(shù)據(jù)庫)。struts作為面向action框架的先驅(qū),它也很自然的成為了先烈。struts中所引入的FormBean, 鏈接管理等概念已經(jīng)在實踐中被證明是無益的。一些新興的框架開始回歸到通用的Map結(jié)構(gòu),直接指定跳轉(zhuǎn)頁面,或者利用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. 橫向延展:分層之后必然導向各個層面的獨立發(fā)展,我們的視野自然也會擴大到單個頁面之外,看到一個層面上更多元素之間的相互作用.在面向?qū)ο笳Z言大行其道的今天,繼承(inheritance)無疑是多數(shù)人首先想到的程序結(jié)構(gòu)組織手段.后臺action可以很自然的利用java語言自身的繼承機制,配置文件中也可以定義類似的extends或者parent屬性.但是對于前臺頁面一般卻很少有適用的抽象手段,于是便有人致力于前臺頁面的對象語言化:首先將前臺頁面采用某種對象語言表達,然后再利用對象語言內(nèi)置的結(jié)構(gòu)抽象機制.放棄界面的可描述性,將其轉(zhuǎn)化為某種活動對象,在我看來是一種錯誤的方向.而JSF(JavaServerFace)規(guī)范卻似乎想在這個方向上越走越遠.JSF早期設(shè)計中存在的一個嚴重問題是延續(xù)了面向?qū)ο笳Z言中的狀態(tài)與行為綁定的組織方式.這造成每次訪問后臺頁面都要重建整個Component Tree, 無法實現(xiàn)頁面結(jié)構(gòu)的有效緩存.而Witrix平臺中的tpl模板語言編譯出的結(jié)構(gòu)是無狀態(tài)的,可以在多個用戶之間重用.

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

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

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

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



    主站蜘蛛池模板: 久久久国产精品无码免费专区| 国产精品亚洲专区无码WEB| 一个人看的免费观看日本视频www 一个人看的免费视频www在线高清动漫 | 插B内射18免费视频| 亚洲国产精品乱码在线观看97| 免费精品久久天干天干| 亚洲午夜久久久影院| 久久国产美女免费观看精品| 亚洲小说区图片区另类春色| aaa毛片视频免费观看| 亚洲伊人久久成综合人影院| 国产精品免费αv视频| 国产A在亚洲线播放| 久久国产乱子伦精品免费不卡| 亚洲成色在线综合网站 | 一级毛片完整版免费播放一区| 久久青青草原亚洲av无码| 又硬又粗又长又爽免费看| 自拍偷自拍亚洲精品被多人伦好爽| 在线播放国产不卡免费视频| 亚洲精品无码久久久久去q| 青柠影视在线观看免费高清 | 国产午夜亚洲精品不卡| 国产亚洲一区区二区在线| 免费国产在线视频| 亚洲国产视频一区| 精品国产免费观看久久久| 免费在线人人电影网| 亚洲AV无码一区二区三区系列| 99视频免费观看| 亚洲中文字幕无码亚洲成A人片| 国产男女猛烈无遮挡免费视频| 一级看片免费视频| 亚洲色图在线播放| 成人黄动漫画免费网站视频 | 亚洲av无码一区二区三区观看| 日韩一区二区免费视频| 中文字幕乱理片免费完整的| 亚洲沟沟美女亚洲沟沟| 四虎永久免费观看| 日本xxxx色视频在线观看免费|