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

          java中最常用的數據結構類型是Map和List, 它們也是Container的兩種基本模式,一個是根據特征值定位,一個是根據地址定位。 它們共同的一個特征是表達了數據之間的直接的,短程的一種相關性。另一種常見的數據結構Tree則表達了數據之間的一種長程的關聯:根節點與其所有層次上 的子節點之間都存在著關聯。 文件系統,組織機構, XML文檔等都可以對應為Tree數據結構。在描述樹形結構的時候,我們經常使用XML文件, 但是XML文件在程序中操縱起來并不方便,這其中的一個重要原因是XML是面向文檔的,即操縱XML的API返回的和使用的都只能是文本字符串,而不能直 接使用程序中常見的其他數據結構。在witrix平臺中操縱Tree結構的標準接口是TreeNode類,它的設計是面向應用的,即節點的屬性值為 Object類型而不是String類型。

          Tree由三部分組成: 屬性,值, 子節點

          class TreeNode implements IVariant{
           List getChildren();

           int getChildCount();
           TreeNode child(int index);

           /** 當name對應的節點不存在時將會自動創建該節點 */
           TreeNode child(String name);

              /** 當name對應的節點不存在時返回null */
           TreeNode existingChild(String name);

           Map getAttributes();
           IVariant attribute(String name);
           void setAttribute(String name, Object attrValue);
          }

          TreeNode.attribute(name)返回的是IVariant接口,例如
          boolean defaultValue = true;
          boolean b = node.child("subA").attribute("attrB").booleanValue(defaultValue);

          TreeNode本身也是IVariant接口的一個實現,例如
          int i = ode.intValue();

          通過使用IVariant接口,我們實現了強類型的java語言與弱類型的xml文本之間的自然轉換,在轉換過程中還可以指定缺省值,這些都極大的簡化了實際應用時的編碼量。

          posted @ 2005-11-19 10:59 canonical 閱讀(353) | 評論 (0)編輯 收藏

             CRUD(Create, Read,Update, Delete)操作中最難處理的是查詢。因為查詢總是多樣化的,如果每個特定查詢調用都編制一個對象方法,則維護量太大且擴展性很差。如果編制一個通用的 查詢接口,一般的做法是直接以SQL文本作為參數,但這樣就幾乎喪失了封裝的意義。這里的核心問題是Query本身是復雜的,我們應該將它對象化為一個 類,在程序中控制Query的結構,而一個文本對象與一個復雜的Java結構對象的差異就在于對于文本對象我們很難有什么假定,因而在程序中也很難編制通 用的程序對其進行處理,一般只能對它進行傳遞。實際上,文本中描述的結構存在于java程序之外!當然,我們可以利用Parser來重新發現這種結構,那 最容易使用的Parser就是xml parser了,所以我們應該將Query的結構建立在xml描述的基礎上。
          edu.thu.search.Query類直接體現了對主題域的通用查詢條件。(對比我對數據倉庫模型的描述)
          class Query{
              List getFields();
           TreeNode getCondition();
          }
          查 詢條件主要通過TreeNode進行顯式建模,使得程序有可能對它進行進一步的處理。例如,在DataSource處理Query之前,權限配置模塊可以 將附加約束直接追加到現有查詢條件之后,實現對數據權限的行級控制。因為把Fields明確分離出來,我們也可以做到對權限的列級控制。
          Query類的使用示例如下:
          Query.begin().fields(TEST_FIELDS)
                       .condition().eq(ID,"3")
             .end().resultType(IQueriable.TYPE_ROW_MAP)
             .findOne(dataSource).mapValue();
          這里的調用接口的設計基本遵循與SQL類相同的風格,只是面向主題域而不是直接針對SQL語言的封裝。

          posted @ 2005-11-19 10:58 canonical 閱讀(908) | 評論 (0)編輯 收藏

              新手總是有很多不好的代碼習慣. 最常見的一個是不使用臨時變量.例如
              for(int i=0;i<myList.size();i++){
                  otherList.get(i).getSomeVar().getName();
                  otherList.get(i).getSomeVar().getValue();
              }
              這種做法有如下后果:
              1. 代碼冗長, 容易出錯, 例如循環體中的某個i寫成了j
              2. 函數調用終究是要耗費時間的, 在一個循環體中的調用往往對性能有可見的影響. 特別是當函數動態裝載數據的時候, 例如每次調用該函數都查詢數據庫, 這種不使用臨時變量的方法將會為系統留下性能隱患.
              3. 一條很長的語句如果不是為流式調用而設計的, 則這種調用方式會影響到我們的調試工作. 例如 當某個中間步驟返回空指針時, 程序會拋出NullPointerException異常, 而我們得到的信息只是某一行存在空指針異常, 但是無法定位到具體是哪個步驟. 當某個中間步驟返回的值不是null但也不是我們所期望的值的時候, 我們同樣難以診斷出具體出錯的步驟. 使用臨時變量將會為調試提供便利
                int i,n=myList.size();
                for(i=0;i<n;i++){
                    MyVar var = otherList.get(i);
                    var.getName();
                    var.getValue();
                    ...
                }
                在需要的時候我們可以在出錯語句處加上斷點, 或者直接輸出可疑的變量值.
              4. 長語句不利于抽象出子函數. 例如在第二種方式中我們抽象出子函數的難度比第一種方式小
                 void processVar(MyVar var){
                     var.getName();
                     var.getValue();
                 }

              造成這些習慣的原因很耐人尋味, 我猜想缺乏抽象能力似乎是最基本的原因, 畢竟為變量起一個名字也是最簡單的抽象步驟之一.

          posted @ 2005-11-17 11:55 canonical 閱讀(432) | 評論 (0)編輯 收藏

              軟件世界與真實的,物理的世界有著本質的不同,其中一點在于軟件中的規則是根據需求制訂的而不是先驗的。我們在研究物理世界的時候,多少會有些唯物主義, 即紛繁蕪雜的表象下蘊含著自恰的,不變的規律。物理學的建模是多方位的,多層次的。同一個規律,在不同的簡化條件和不同的環境中我們會賦予它不同的名字。 在不同的抽象層面上,我們也可能會建立不同的模型。嚴格的說起來,這些模型之間可能存在著不一致性,但我們相信,存在著一個絕對精確的模型:無限的細節, 無限的關聯,完美的,自恰的,而我們所建立的所有物理模型都只是對該終極模型在某個層次,某個角度上的近似抽象,而每一個模型都有著自己的適用范圍。很多 時候物理學的建模是粗魯的,拋棄了大量似乎必須的要素,只因為物理學家相信物理學的直覺能夠將我們引導到正確的道路,不論我們做出什么樣的簡化和假設,只 要它是物理的,最終都會回歸到真實的世界。
              軟件是人為構造出來的,其體現的運行規律由外部需求所決定,而無法形成自我的證明。領域模型(Domain Model)隱喻式的期望能夠建立穩定的邏輯層,可這注定是困難的。我們在軟件設計中希望分層,職責單一,進行正交化設計。可是一個復雜系統的邏輯分解注 定是無法正交化的。非此即彼只存在于抽象的世界。多個復雜性層次上的結構交織在一起,使得我們難以建立穩定的根基。因為缺乏先驗的支配規則,我們鼓吹需求 到實現的1:1映射,實際上只是希望通過貧乏的唯一性來維護演變中的自恰性。真正實現了1:1映射是不是在系統中引入了人為的剛性? 在一定的情景下,為了達到最適的模型,我們需要各種Facade,我們需要1:n映射,抑或是m:n映射。被割裂了的聯系仍然需要通過各種service 在系統中重建出來。
           在建筑學的隱喻中,建筑設計師與建筑工人之間還存在著一個角色:土木工程師。他在物理結構的層面上而不是應用意義上把握整體 工程。在結構層次上我們是能夠進行有效的推理和判斷的。在軟件中也是一樣,拋去對象的業務含義,我們可以把它理解為一個Map,那對它可以進行那些操作是 可以預知的。只是我們對于軟件結構層面的了解還是太膚淺了。每個項目,大量的時間花費在編寫那些低層的與業務無關的模塊(或者說可以抽象出這些模塊),這 就如同每次建筑,都從制造磚塊開始一樣。材料的準備不是一朝一夕之功。在結構層上我們必須對系統形成深刻的理解,這不僅僅是業務建模的問題。

          posted @ 2005-11-16 20:10 canonical 閱讀(606) | 評論 (1)編輯 收藏

          有人認為jsplet中使用session是個缺點,關于這一點,我想起一件以前聽來的事情。我們都知道Linux的內核是常駐內存,不換頁的(不知道最 新的內核是否已經有所改變),Torvalds認為內核換頁對系統性能有巨大影響,是愚蠢的想法,所以Linux內核不能換頁。據陳榕說,NT內核是可換 頁的,而微軟內部有一個小組,專門編寫工具,對已經編譯好的操作系統二機制代碼進行優化,調整,最終結果是NT內核可以換頁,但幾乎不換頁,這才是微軟可 怕的技術實力。
          對于簡單的應用,session可以隨意使用,而對那些性能要求極高的應用,每一個系統架構師都會如履薄冰,簡單的依靠全局Cache不是真正的解決方 案,在每一個細節上我們所需要的是更多的控制權而不是更多的限制。jsplet通過objectScope可以對session進行有效的使用,這是它的 優點而不是缺點。在一個有效的框架下,才能進行真正有序的控制。只有在對系統擁有更多假設的情況下,才能把控制施加在關鍵點上。

          順便提一下,現在有些人一提到性能,就對jsp直搖頭,而對第三方產品卻熱情擁抱。目前在java社區內普遍存在著一種對官方標準的漠視或者反感,不知道這是怎么回事。

          posted @ 2005-11-16 20:07 canonical 閱讀(269) | 評論 (0)編輯 收藏

          在時間軸上定位一般比較麻煩,我們可以編寫大量的get函數來得到特殊時間點,如 getFirstDayOfMonth(int year,int month), getFirstDayOfNextMonth(int year, int month),這不如采用如下正交化的流式設計。
          EasyCalendar cal =

              new EasyCalendar().toYear(2001).toMonth(1).toFirstDayOfMonth().toFirstDayOfWeek();

          posted @ 2005-11-16 19:28 canonical 閱讀(404) | 評論 (0)編輯 收藏

          tpl是witrix開發平臺中的動態xml標簽技術,其基本特點表現為如下三個方面:
          1. 執行能力
           xml本身只是對數據的描述,而沒有循環和判斷的能力。
           在tpl中<c:forEach>和<c:if>標簽可以完成程序語言的執行功能,并定義了<c:tile>, <c:iif>等更方便的標簽。

          2. 抽象能力
             獲得抽象能力,首要的一點是使得創建新概念的成本極低。很少有人大量開發jsp tag,原因就是開發tag過于麻煩,而且調整不方便。另外開發出的tag如果粒度太小,大量使用的時候是對性能的致命傷害。
             tpl首先需要經過編譯,而不是象jsp tag那樣完全動態運行,而且tpl編譯出的結果是無狀態的,因此解決了性能上的問題。
             在tpl中導入外部模板的語法非常簡單,可以實現基本的分解
              <c:include src="xxx.tpl" />
             更重要的是,tpl中定義了完善的庫機制。
          使用庫
              <!-- 導入外部包, 導入時指定名字空間為demo。
                   注意tpl中并沒有完整的名字空間支持,只能作為qName使用
              -->
              <c:lib src="demo_lib.xml" namespace="demo" />

           <!-- 對具有cache:timeout屬性的節點應用cache修飾,即該節點的運行內容被緩存 -->
           <c:decorator type="cache" match="
          //@[cache:timeout]" />

              <div id="blockA">
                  <p>通過tpl:tag屬性可以設定宿主標簽的真實標簽名。這種做法可以方便可視化設計:</p>
                  <input tpl:tag="demo:文本框" value="in block A" otherValue="${varInJsp}" onclick="clickOnBtn()"/>
              </div>

              <div id="blockB">       
                 <p>分頁表格:</p>
                  <img tpl:tag="demo:分頁表格" headers="fieldA,fieldB" pager="${pager}" />
              </div>

              <div id="blockC">
                <p>bodyTag標簽的調用:</p>
                  <demo:循環data>
                      <input type="text" value="${row}" /> <br/>
                  </demo:循環data>
              </div>

              <div id="blockD" cache:timeout="1000s" >
                  <p>條件標簽的調用:</p>
                  <demo:當Num足夠大>
                      <p>當 thisObj中的變量 'num' 的值大于3的時候顯示這句話 </p>
                  </demo:當Num足夠大>
              </div>

          定義庫文件demo_lib.xml
          <!--
               自定義標簽的屬性:
            type: simpleTag, bodyTag 或者 conditionTag, 缺省為simpleTag
            importVars : 每個自定義標簽具有自己的變量空間,需要通過importVars來明確指定從外部變量空間中導入的變量。
            demandArgs: 調用時必須明確給出這些參數的值
            otherArgs: 如果指定了該參數,則調用自定義標簽時能夠使用的參數就必須在demandArgs和otherArgs指定的范圍之內。
          -->
          <demo>
              <!-- 一個簡單的tag示例, 直接輸出變量。這里demandArgs指定調用時必須提供的變量。 -->
           <文本框 demandArgs="value" otherArgs="otherValue,onclick" type="simpleTag" >
            <p> -----------------------------------  </p>
               <!-- 可以使用調用時提供的其他變量,如otherValue-->
            <input size="40" type="text" value="${value} * ${otherValue}" onclick="${onclick}"/>
            <p> -----------------------------------</p>
           </文本框>

              <!-- 一個自動分頁表格,要求傳入headers(List類型)指定表頭,pager(Pager類型)提供數據 -->
           <分頁表格 demandArgs="headers,pager">
               <!-- 從外部導入tpl文件 -->
            <c:include src="flex_table.tpl" />
           </分頁表格>

           <!-- 一個bodyTag示例: 循環處理thisObj中的變量data中的每一行。
                importVars從調用環境中自動導入變量而不需要通過調用參數直接指定。
                當然如果調用參數中指定的變量與importVars中指定的變量重復,則調用參數會覆蓋importVars.
              -->
           <循環data importVars="thisObj" type="bodyTag">
            <c:forEach var="row" items="${data}">
             <!-- tagBody為調用時標簽的內容 -->
             <cp:compile src="${tagBody}" />
            </c:forEach>
           </循環data>

           <!-- 一個條件標簽的示例.
                條件標簽一般不應該輸出文本,而是返回一個bool值。僅當返回true的時候,調用時標簽的內容才會被運行。
           -->
           <當Num足夠大 importVars="thisObj" type="conditionTag">
            <l:gt name="num" value="3" />
           </當Num足夠大>
          </demo>

          注 意到bodyTag和conditionTag使得我們可以將循環(容器)邏輯和判斷邏輯抽象成有意義的概念,而不再是一些執行的指令。這種抽象能力的應 用非常依賴于xml的自描述特性,我們不需要付出太大的努力,就可以在lib中封裝出一個有意義的概念來! 而且tag的參數可以指定,可以缺省,存在多種選擇,也對應著多種邏輯模型。
          通過<c:decorator>的用法可以看到,因為xml明確定義了結構,使得我們可以輕易的實施類似AOP的功能。

          3. 集成能力
             首先,tpl完全符合xml規范,與xml世界接軌,可以自由的使用xslt。例如,在
             任何標簽中都可以指定tpl:xdecorator屬性, tpl在編譯之前首先會應用指定的xslt文件進行變換,對變換后的結果再進行編譯。
             <anyTagName tpl:xdecorator="some_xslt.xslt">
            ...
             </anyTagName>
             其次,tpl可以使用屬性標記,即tpl標簽不僅僅可以通過標簽名來標識,而且可以通過tpl:tag屬性來標識。例如:
             <input tpl:decorator="demo:文本框" />
             與 <demo:文本框 />等效。
             這種做法避免了tpl侵入html模型,使得我們可以利用現有工具對tpl進行所見即所得(WISIWIG)的設計。

             再次, 在tpl中使用EL(Expression Language)語言,集成java數據模型。

             第四, 在tpl中可以采用如下方式實現強類型化,完成與java的接口。
             interface ITest{
               void test(String name, int value);
             }

             <o:class name="MyClass" implements="ITest">
              <test args="name,value" >
             ...
              </test>
             </o:class>
             這種能力可以在數據源的filter中使用。

             第五, tpl可以輕易的集成其它xml技術。例如,tpl集成了ant
             <ant:run>
            <echo message="xxx" />
             </ant:run>
             因此,我們立刻擁有了ant的數千個功能標簽。

          posted @ 2005-11-16 19:23 canonical 閱讀(544) | 評論 (0)編輯 收藏

          經常有人說XX技術是面向復雜應用的,對于常規應用如果采用那是得不償失。我想很多情況下這只是體現了該技術的不適 應性。我主張系統設計應該盡量體現一種共振原則,即系統架構只有一個,但是面向復雜的應用,它表現出復雜的特性,能夠辨識精細的概念,而面向簡單應用,可 以實現一種優雅的退化(degradation), 對外暴露出一種簡單的結構。抽象的說,我們所建立的不是一個孤立的模型,而是一個模型的系列,不是一個綁定應用的solution而是一種 strategy,在每一個復雜性層次上,都存在著對應的解決方案,而不同復雜性層次上的模型之間又存在著清晰的演化路徑。這也是我所提出的級列設計理論 的要點之一。

          在jsplet框架的設計中,充分體現了這一點。
          jsplet中通過如下url格式來訪問web應用:
          view.jsp?objectName=xxx&objectEvent=yyy&eventTarget=ZZZ
          其中objectName的格式規定如下
             
          objectScope@objectType$objectInstanceId
          在系統的規模較小,不需要對象的生命周期控制的情況下,我們可以將所有對象都放在根路徑下/。
          在同類型的對象只有一個實例的情況下,我們可以不使用objectInstanceId。
          在一個頁面對應一個模型對象的情況下,我們可以不使用eventTarget參數。
          當頁面比較簡單的情況下,我們可以直接使用jsp輸出頁面,而不用使用其它頁面模板機制。(采用jsp作為view原因很簡單,jsp是標準,它應該成為其它所有第三方模板技術的入口)

          為了支持jsplet的url中所體現出的概念,只需要1000行不到的代碼,但是隨著復雜性的增加,我們可以增加越來越多的功能,這體現在url格式的細化上,但是整體的程序結構并沒有發生改變。

          posted @ 2005-11-15 12:35 canonical 閱讀(253) | 評論 (0)編輯 收藏

          jsplet中的對象化并不是一種巧妙的trick,而是一種設計上的必然。現在大家言 必稱OO,可OO到底意味著什么,除了書本上的話語,你能不能用自己的話描述一下,能否體會到那種必然。OO如果是一個有效的概念,它在軟件以外的領域是 否有著對應。按照早期教科書的說法,OO是為了模擬現實世界,這種說法只是反映了設計上的一種困境,一種思想上的貧乏。面向對象最直接的意義在于標示了狀 態與行為之間的耦合,此后在程序中可以用一種顯示的,一致的方式來操縱這個集合體。在界面上,我們看到一個組件,在模型層,我們看到的還是那個對象,在配 置文件里我們還能清晰的辨別出它來。可在webwork這種面向action的框架中,package看起來像對象,在action層卻不見了,當我們需 要同時使用兩個action的功能的時候(如同時列出role和user),以前的action不能用了,只能再寫一個。想一想,我們最少需要多少概念, 最少需要做多少工作,才能在軟件中建立一個合適的概念框架,怎樣才能保持這種框架中的張力。

          posted @ 2005-11-15 12:34 canonical 閱讀(249) | 評論 (0)編輯 收藏

          關于jsplet中的object生命周期的管理以及使用拉模式,如果套用現在流行的設計術語,那就是涉及到所謂的IoC設計(控制反轉)
          IoC 的Container現在很受追捧, 但真正的IoC設計思想并沒有引起大家的重視。也許大多數人使用的都是成品吧,以至于把成品的功能等價于其所依賴的設計原理。Spring等所建立的 IoC更準確的說法是Dependency Injection,只是IoC的一種體現。其基本思想是一個對象并不控制所有與它相關的部分,而是把控制權交給使用對象的人。這里重要的就是控制流(信 息流)的反轉。
          對象生命周期的管理也是這樣,并不是由一個Manager猜測用戶是否使用該對象,而是由用戶直接標明他的態度,直接發出指令。
          參 考一下桌面應用中的資源控制手段,我們打開一個窗口,與系統進行交互,此時占用資源,關閉窗口,則該窗口以及其子窗口所占用的資源都釋放。在jsplet 中對象控制策略類似。當用戶從某個功能區退出的時候,即當用戶訪問其它scope中對象而放棄當前objectScope的時候,開始做資源清理工作。即 用戶的行為和意向直接驅動著系統的對象管理層。當然,如果用戶一直不發出調用,那么系統只能猜測用戶的行為,用戶是否已斷線或者正在思考?在這種情況下, 如果控制資源,則需要通過AOP給thisObj 加上類似EJB的功能。

          posted @ 2005-11-15 12:34 canonical 閱讀(243) | 評論 (0)編輯 收藏

          僅列出標題
          共18頁: First 上一頁 10 11 12 13 14 15 16 17 18 下一頁 
          主站蜘蛛池模板: 凤阳县| 安远县| 望城县| 赫章县| 双牌县| 呼和浩特市| 漠河县| 镇坪县| 东宁县| 青龙| 乌审旗| 友谊县| 深州市| 宜兰县| 哈密市| 昭通市| 庐江县| 基隆市| 德阳市| 鄂尔多斯市| 长泰县| 娄烦县| 苍溪县| 鄂托克前旗| 称多县| 丹江口市| 江阴市| 秭归县| 简阳市| 房产| 荣成市| 福贡县| 格尔木市| 陵川县| 阳江市| 甘洛县| 黔西县| 左贡县| 思南县| 昌都县| 曲阜市|