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

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

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

    iNeo

      BlogJava :: 首頁 :: 聯(lián)系 :: 聚合  :: 管理
      30 Posts :: 8 Stories :: 2 Comments :: 0 Trackbacks

    2005年12月30日 #

    我的tomcat工程建在:d:\eclipse\workspace\luc,索引文件是d:\eclipse\workspace\luc\public\index,建立索引的時(shí)候路徑為"luc\\public\\index",但在搜索的時(shí)候,我用
    searcher = new IndexSearcher(“l(fā)uc\\public\\index”);
    報(bào)錯(cuò)了,因?yàn)閘ucene在FSDirectory里將我的路徑給new File(file.getCanonicalPath());
    但奇怪的是file.getCanonicalPath()出來路徑不對(duì)呀
    錯(cuò)誤是
    java.io.IOException: D:\eclipse\luc\public\index not a directory
    應(yīng)該是d:\eclipse\workspace\luc\public\index 才對(duì)的
    郁悶很久了,現(xiàn)在還沒辦法解決!!!!!!!!!!!!!!!!!!!!!!!!!!
    posted @ 2006-08-03 09:12 只牽這只狗 閱讀(327) | 評(píng)論 (0)編輯 收藏

    今天上午升級(jí) Eclipse 3.1.2 版本,完了之后就想找個(gè)數(shù)據(jù)庫的插件,但花了近 2 個(gè)小時(shí)后得出的結(jié)論是:還沒有支持 3.1.x 版本的數(shù)據(jù)庫插件,郁悶的不行。看看 eclipse3.1.12 的發(fā)行日期—— 2005.12.26 ,咳,去年 12 月份出的,想不到到現(xiàn)在還沒有支持的版本。當(dāng)然也可能是我沒找到。如果哪位兄臺(tái)能給個(gè)支持 3.1.x 版本的數(shù)據(jù)庫插件,將不甚感激!

    雖然沒找到正主,但還是找到了一些 Eclipse3.0.x 版本可用的版本,以共將來參考。

    SQLExplorer
    SQLExplorer 可以通過JDBC訪問幾乎任何一種數(shù)據(jù)庫。同時(shí)也支持像Hibernate這樣的工具訪問數(shù)據(jù)庫?,F(xiàn)在的版本是SQLExporer 2.2.4 released

    下栽地址:http://sourceforge.net/projects/eclipsesql

    JFaceDBC

    是一個(gè)很好的 SQL 控制臺(tái) , 支持各類主流數(shù)據(jù)庫?,F(xiàn)在的版本是 JFaceDbc 3.0

    下栽地址:http://sourceforge.net/projects/jfacedbc

    Quantum
    Quantum 是一個(gè)數(shù)據(jù)庫訪問插件.它當(dāng)前支持的數(shù)據(jù)庫有:Postgres,MySQL,Adabas,DB2,Oracle與有JDBC驅(qū)動(dòng)的數(shù)據(jù)庫.它可以顯示表格,視圖并提供一個(gè)語法可高亮顯示的SQL編輯器

    com.quantum.feature_3.0.1.bin.dist

    下栽地址:http://sourceforge.net/project/showfiles.php?group_id=7746&package_id=57047

    posted @ 2006-03-30 12:42 只牽這只狗 閱讀(3637) | 評(píng)論 (1)編輯 收藏

    TMD..........

    posted @ 2006-03-15 16:54 只牽這只狗 閱讀(220) | 評(píng)論 (0)編輯 收藏

    任何人都可以重構(gòu)

    使用 Eclipse 自動(dòng)重構(gòu)特性的方法與原因

     

     

    未顯示需要 JavaScript 的文檔選項(xiàng)


    對(duì)此頁的評(píng)價(jià)

     


    級(jí)別: 初級(jí)

    David Gallardo, 獨(dú)立軟件顧問和作家

    2003 年 11 月 10 日

    Eclipse 提供了一組強(qiáng)大的自動(dòng)重構(gòu)(refactoring)功能,這些功能穿插在其他功能當(dāng)中,使您能夠重命名 Java元素,移動(dòng)類和包,從具體的類中創(chuàng)建接口,將嵌套的類變成頂級(jí)類,以及從舊方法的代碼片斷中析取出新的方法。您熟悉了 Eclipse 的重構(gòu)工具之后,就掌握了一種提高生產(chǎn)率的好方法。本文綜覽Eclipse 的重構(gòu)特性,并通過例子闡明了使用這些特性的方法與原因。

    為什么重構(gòu)?

    重構(gòu)是指在不改變程序功能的前提下改變其結(jié)構(gòu)。重構(gòu)是一項(xiàng)功能強(qiáng)大的技術(shù),但是執(zhí)行起來需要倍加小心才行。主要的危險(xiǎn)在于可能在不經(jīng)意中引入一些錯(cuò)誤,尤其是在進(jìn)行手工重構(gòu)的時(shí)候更是如此。這種危險(xiǎn)引發(fā)了對(duì)重構(gòu)技術(shù)的普遍批評(píng):當(dāng)代碼不會(huì)崩潰的時(shí)候?yàn)槭裁匆薷乃兀?

    您需要進(jìn)行代碼重構(gòu)的原因可能有以下幾個(gè):傳說中的第一個(gè)原因是:需要繼承為某個(gè)古老產(chǎn)品而開發(fā)的年代久遠(yuǎn)的代碼,或者突然碰到這些代碼。最初的開發(fā)團(tuán)隊(duì)已經(jīng)不在了。我們必須創(chuàng)建增加了新特性的新版本軟件,但是這些代碼已經(jīng)無法理解了。新的開發(fā)隊(duì)伍夜以繼日地工作,破譯代碼然后映射代碼,經(jīng)過大量的規(guī)劃與設(shè)計(jì)之后,人們將這些代碼分割成碎片。歷經(jīng)重重磨難之后,所有這些東西都按照新版本的要求歸位了。這是英雄般的重構(gòu)故事,幾乎沒有人能在經(jīng)歷了這些之后活著講述這樣的故事。

    還有一種現(xiàn)實(shí)一些的情況是項(xiàng)目中加入了新的需求,需要對(duì)設(shè)計(jì)進(jìn)行修改。至于是因?yàn)樵谧畛醯囊?guī)劃過程中失察,還是由于采用了迭代式的開發(fā)過程(比如敏捷開發(fā),或者是測(cè)試驅(qū)動(dòng)的開發(fā))而在開發(fā)過程中有意引入需求,這兩者并沒有實(shí)質(zhì)性的區(qū)別。這樣的重構(gòu)的規(guī)模要小得多,其內(nèi)容一般涉及通過引入接口或者抽象類來更改類的繼承關(guān)系,以及對(duì)類進(jìn)行分割和重新組織,等等。

    重構(gòu)的最后一個(gè)原因是,當(dāng)存在可用的自動(dòng)重構(gòu)工具時(shí),可以有一個(gè)用來預(yù)先生成代碼的快捷方式——就好比在您無法確定如何拼寫某個(gè)單詞的時(shí)候,可以用某種拼寫檢查工具輸入這個(gè)單詞。比如說,您可以用這種平淡無奇的重構(gòu)方法生成 getter 和 setter 方法,一旦熟悉了這樣的工具,它就可以為您節(jié)省很多的時(shí)間。

    Eclipse 的重構(gòu)工具無意進(jìn)行英雄級(jí)的重構(gòu)——適合這種規(guī)模的工具幾乎沒有——但是不論是否用到敏捷開發(fā)技術(shù),Eclipse 的工具對(duì)于一般程序員修改代碼的工作都具有無法衡量的價(jià)值。畢竟任何復(fù)雜的操作只要能夠自動(dòng)進(jìn)行,就可以不那么煩悶了。只要您知道 Eclipse 實(shí)現(xiàn)了什么樣的重構(gòu)工具,并理解了它們的適用情況,您的生產(chǎn)力就會(huì)得到極大的提高。

    要降低對(duì)代碼造成破壞的風(fēng)險(xiǎn),有兩種重要的方法。第一種方法是對(duì)代碼進(jìn)行一套完全徹底的單元測(cè)試:在重構(gòu)之前和之后都必須通過這樣的測(cè)試。第二種方法是使用自動(dòng)化的工具來進(jìn)行重構(gòu),比如說 Eclipse 的重構(gòu)特性。

    將徹底的測(cè)試與自動(dòng)化重構(gòu)結(jié)合起來就會(huì)更加有效了,這樣重構(gòu)也就從一種神秘的藝術(shù)變成了有用的日常工具。為了增加新的功能或者改進(jìn)代碼的可維護(hù)性,我們可以在不影響原有代碼功能的基礎(chǔ)上迅速且安全地改變其結(jié)構(gòu)。這種能力會(huì)對(duì)您設(shè)計(jì)和開發(fā)代碼的方式產(chǎn)生極大的影響,即便是您沒有將其結(jié)合到正式的敏捷方法中也沒有關(guān)系。



    回頁首


    Eclipse 中重構(gòu)的類型

    Eclipse 的重構(gòu)工具可以分為三大類(下面的順序也就是這些工具在 Refactoring 菜單中出現(xiàn)的順序):

    1. 對(duì)代碼進(jìn)行重命名以及改變代碼的物理結(jié)構(gòu),包括對(duì)屬性、變量、類以及接口重新命名,還有移動(dòng)包和類等。
    2. 改變類一級(jí)的代碼邏輯結(jié)構(gòu),包括將匿名類轉(zhuǎn)變?yōu)榍短最?,將嵌套類轉(zhuǎn)變?yōu)轫敿?jí)類、根據(jù)具體的類創(chuàng)建接口,以及從一個(gè)類中將方法或者屬性移到子類或者父類中。
    3. 改變一個(gè)類內(nèi)部的代碼,包括將局部變量變成類的屬性、將某個(gè)方法中選中部分的代碼變成一個(gè)獨(dú)立的方法、以及為屬性生成 getter 和 setter 方法。

    還有幾個(gè)重構(gòu)工具并不能完全歸入這三個(gè)種類,特別是 Change Method Signature,不過在本文中還是將這個(gè)工具歸入第三類。除了這種例外情況以外,本文下面幾節(jié)都是按照上面的順序來討論 Eclipse 重構(gòu)工具的。



    回頁首


    物理重組與重命名

    顯然,您即便沒有特別的工具,也可以在文件系統(tǒng)中重命名文件或者是移動(dòng)文件,但是如果操作對(duì)象是 Java 源代碼文件,您就需要編輯很多文件,更新其中的 import package 語句。與此類似,用某種文本編輯器的搜索與替換功能也可以很容易地給類、方法和變量重新命名,但是這樣做的時(shí)候必須十分小心,因?yàn)椴煌念惪赡芫哂忻Q相似的方法或者變量;要是從頭到尾檢查項(xiàng)目中所有的文件,來保證每個(gè)東西的標(biāo)識(shí)和修改的正確性,那可真夠乏味的。

    Eclipse 的 Rename 和 Move 工具能夠十分聰明地在整個(gè)項(xiàng)目中完成這樣的修改,而不需要用戶的干涉。這是因?yàn)?Eclipse 可以理解代碼的語義,從而能夠識(shí)別出對(duì)某個(gè)特定方法、變量或者類名稱的引用。簡(jiǎn)化這一任務(wù)有助于確保方法、變量和類的名稱能夠清晰地指示其用途。

    我們經(jīng)??梢园l(fā)現(xiàn)代碼的名字不恰當(dāng)或者令人容易誤解,這是因?yàn)榇a與最初設(shè)計(jì)的功能有所不同。比方說,某個(gè)用來在文件中查找特定單詞的程序也許會(huì)擴(kuò)展為在 Web 頁面中通過 URL 獲取 InputStream 的操作。如果這一輸入流最初叫做 file ,那么就應(yīng)該修改它的名字,以便能反映其新增的更加一般的特性,比方說 sourceStream 。開發(fā)人員經(jīng)常無法成功地修改這些名稱,因?yàn)檫@個(gè)過程是十分混亂和乏味的。這當(dāng)然也會(huì)把下一個(gè)不得不對(duì)這些類進(jìn)行操作的開發(fā)人員弄糊涂。

    要對(duì)某個(gè) Java 元素進(jìn)行重命名,只需要簡(jiǎn)單地從 Package Explorer 視圖中點(diǎn)擊這個(gè)元素,或者從Java 源代碼文件中選中這個(gè)元素,然后選擇菜單項(xiàng) Refactor > Rename。在對(duì)話框中輸入新的名稱,然后選擇是否需要 Eclipse 也改變對(duì)這個(gè)名稱的引用。實(shí)際顯示出來的確切內(nèi)容與您所選元素的類型有關(guān)。比方說,如果選擇的屬性具有 getter 和 setter 方法,那么也就可以同時(shí)更新這些方法的名稱,以反映新的屬性。圖1顯示了一個(gè)簡(jiǎn)單的例子。

    圖 1. 重命名一個(gè)局部變量
    Renaming a local variable

    就像所有的 Eclipse 重構(gòu)操作一樣,當(dāng)您指定了全部用來執(zhí)行重構(gòu)的必要信息之后,您就可以點(diǎn)擊 Preview 按鈕,然后在一個(gè)對(duì)話框中對(duì)比 Eclipse 打算進(jìn)行哪些變更,您可以分別否決或者確認(rèn)每一個(gè)受到影響的文件中的每一項(xiàng)變更。如果您對(duì)于 Eclipse 正確執(zhí)行變更的能力有信心的話,您可以只按下 OK按鈕。顯然,如果您不確定重構(gòu)到底做了什么事情,您就會(huì)想先預(yù)覽一下,但是對(duì)于 Rename 和 Move 這樣簡(jiǎn)單的重構(gòu)而言,通常沒有必要預(yù)覽。

    Move 操作與 Rename 十分相似:您選擇某個(gè) Java 元素(通常是一個(gè)類),為其指定一個(gè)新位置,并定義是否需要更新引用。然后,您可以選擇 Preview檢查變更情況,或者選擇 OK 立即執(zhí)行重構(gòu),如圖2所示。

    圖 2. 將類從一個(gè)包移到另一個(gè)包
    Moving a class

    在某些平臺(tái)上(特別是 Windows),您還可以在 Package Explorer 視圖中通過簡(jiǎn)單拖放的方法將類從一個(gè)包或者文件夾中移到另一個(gè)包或文件夾中。所有的引用都會(huì)自動(dòng)更新。



    回頁首


    重新定義類的關(guān)系

    Eclipse 中有大量的重構(gòu)工具,使您能夠自動(dòng)改變類的關(guān)系。這些重構(gòu)工具并沒有 Eclipse 提供的其他工具那么常用,但是很有價(jià)值,因?yàn)樗鼈兡軌驁?zhí)行非常復(fù)雜的任務(wù)。可以說,當(dāng)它們用得上的時(shí)候,就會(huì)非常有用。

    提升匿名類與嵌套類

    Convert Anonymous Class(轉(zhuǎn)換匿名類)和 Convert Nested Type(轉(zhuǎn)換嵌套類)這兩種重構(gòu)方法比較相似,它們都將某個(gè)類從其當(dāng)前范圍移動(dòng)到包含這個(gè)類的范圍上。

    匿名類是一種語法速寫標(biāo)記,使您能夠在需要實(shí)現(xiàn)某個(gè)抽象類或者接口的地方創(chuàng)建一個(gè)類的實(shí)例,而不需要顯式提供類的名稱。比如在創(chuàng)建用戶界面中的監(jiān)聽器時(shí),就經(jīng)常用到匿名類。在清單1中,假設(shè) Bag 是在其他地方定義的一個(gè)接口,其中聲明了兩個(gè)方法, get() set() 。


    清單 1. Bag 類
     
          public class BagExample
    {
       void processMessage(String msg)
       {
          Bag bag = new Bag()
          {
             Object o;
             public Object get()
             {
                return o;
             }
             public void set(Object o)
             {
                this.o = o;
             }
          };
          bag.set(msg);
          MessagePipe pipe = new MessagePipe();
          pipe.send(bag);
       }
    }
    

    當(dāng)匿名類變得很大,其中的代碼難以閱讀的時(shí)候,您就應(yīng)該考慮將這個(gè)匿名類變成嚴(yán)格意義上的類;為了保持封裝性(換句話說,就是將它隱藏起來,使得不必知道它的外部類不知道它),您應(yīng)該將其變成嵌套類,而不是頂級(jí)類。您可以在這個(gè)匿名類的內(nèi)部點(diǎn)擊,然后選擇 Refactor > Convert Anonymous Class to Nested 就可以了。當(dāng)出現(xiàn)確認(rèn)對(duì)話框的時(shí)候,為這個(gè)類輸入名稱,比如 BagImpl ,然后選擇 Preview或者 OK。這樣,代碼就變成了如清單2所示的情形。


    清單 2. 經(jīng)過重構(gòu)的 Bag 類
     
    
    public class BagExample
    {
       private final class BagImpl implements Bag
       {
          Object o;
          public Object get()
          {
             return o;
          }
          public void set(Object o)
          {
             this.o = o;
          }
       }
           
       void processMessage(String msg)
       {
         Bag bag = new BagImpl();
         bag.set(msg);
         MessagePipe pipe = new MessagePipe();
         pipe.send(bag);
       }
    }

    當(dāng)您想讓其他的類使用某個(gè)嵌套類時(shí),Convert Nested Type to Top Level 就很有用了。比方說,您可以在一個(gè)類中使用值對(duì)象,就像上面的 BagImpl 類那樣。如果您后來又決定應(yīng)該在多個(gè)類之間共享這個(gè)數(shù)據(jù),那么重構(gòu)操作就能從這個(gè)嵌套類中創(chuàng)建新的類文件。您可以在源代碼文件中高亮選中類名稱(或者在 Outline 視圖中點(diǎn)擊類的名稱),然后選擇 Refactor > Convert Nested Type to Top Level,這樣就實(shí)現(xiàn)了重構(gòu)。

    這種重構(gòu)要求您為裝入實(shí)例提供一個(gè)名字。重構(gòu)工具也會(huì)提供建議的名稱,比如 example ,您可以接受這個(gè)名字。這個(gè)名字的意思過一會(huì)兒就清楚了。點(diǎn)擊 OK 之后,外層類 BagExample 就會(huì)變成清單3所示的樣子。


    清單 3. 經(jīng)過重構(gòu)的 Bag 類
    
    public class BagExample
    {
       void processMessage(String msg)
       {
          Bag bag = new BagImpl(this);
          bag.set(msg);
          MessagePipe pipe = new MessagePipe();
          pipe.send(bag);
       }
    }
    

    請(qǐng)注意,當(dāng)一個(gè)類是嵌套類的時(shí)候,它可以訪問其外層類的成員。為了保留這種功能,重構(gòu)過程將一個(gè)裝入類 BagExample 的實(shí)例放在前面那個(gè)嵌套類中。這就是之前要求您輸入名稱的實(shí)例變量。同時(shí)也創(chuàng)建了用于設(shè)置這個(gè)實(shí)例變量的構(gòu)造函數(shù)。重構(gòu)過程創(chuàng)建的新類 BagImpl 如清單4所示。


    清單 4. BagImpl 類
      
    final class BagImpl implements Bag
    {
       private final BagExample example;
       /**
        * @paramBagExample
        */
      BagImpl(BagExample example)
       {
          this.example = example;
          // TODO Auto-generated constructor stub
       }
       Object o;
       public Object get()
       {
          return o;
       }
       public void set(Object o)
       {
          this.o = o;
       }
    }
    

    如果您的情況與這個(gè)例子相同,不需要保留對(duì) BagExample 的訪問,您也可以很安全地刪除這個(gè)實(shí)例變量與構(gòu)造函數(shù),將 BagExample 類中的代碼改成缺省的無參數(shù)構(gòu)造函數(shù)。

    在類繼承關(guān)系內(nèi)移動(dòng)成員

    還有兩個(gè)重構(gòu)工具,Push Down 和 Pull Up,分別實(shí)現(xiàn)將類方法或者屬性從一個(gè)類移動(dòng)到其子類或父類中。假設(shè)您有一個(gè)名為 Vehicle 的抽象類,其定義如清單5所示。


    清單 5. 抽象的 Vehicle 類
    
    public abstract class Vehicle
    {
       protected int passengers;
       protected String motor;
       
       public int getPassengers()
       {
          return passengers;
       }
       public void setPassengers(int i)
       {
          passengers = i;
       }
       public String getMotor()
       {
          return motor;
       }
       public void setMotor(String string)
       {
          motor = string;
       }
    }
    

    您還有一個(gè) Vehicle 的子類,類名為 Automobile ,如清單6所示。


    清單6. Automobile 類
    
    public class Automobile extends Vehicle
    {
       private String make;
       private String model;
       public String getMake()
       {
          return make;
       }
       public String getModel()
       {
          return model;
       }
       public void setMake(String string)
       {
          make = string;
       }
       public void setModel(String string)
       {
          model = string;
       }
    }
    

    請(qǐng)注意, Vehicle 有一個(gè)屬性是 motor 。如果您知道您將永遠(yuǎn)只處理汽車,那么這樣做就好了;但是如果您也允許出現(xiàn)劃艇之類的東西,那么您就需要將 motor 屬性從 Vehicle 類下放到 Automobile 類中。為此,您可以在 Outline 視圖中選擇 motor ,然后選擇 Refactor > Push Down。

    Eclipse 還是挺聰明的,它知道您不可能總是單單移動(dòng)某個(gè)屬性本身,因此還提供了 Add Required 按鈕,不過在 Eclipse 2.1 中,這個(gè)功能并不總是能正確地工作。您需要驗(yàn)證一下,看所有依賴于這個(gè)屬性的方法是否都推到了下一層。在本例中,這樣的方法有兩個(gè),即與 motor 相伴的 getter 和 setter 方法,如圖3所示。

    圖 3. 加入所需的成員
    Adding required members

    在按過 OK按鈕之后, motor 屬性以及 getMotor() setMotor() 方法就會(huì)移動(dòng)到 Automobile 類中。清單7顯示了在進(jìn)行了這次重構(gòu)之后 Automobile 類的情形。


    清單 7. 經(jīng)過重構(gòu)的 Automobile 類
    public class Automobile extends Vehicle
    {
       private String make;
       private String model;
       protected String motor;
       public String getMake()
       {
          return make;
       }
       public String getModel()
       {
          return model;
       }
       public void setMake(String string)
       {
          make = string;
       }
       public void setModel(String string)
       {
          model = string;
       }
       public String getMotor()
       {
          return motor;
       }
       public void setMotor(String string)
       {
          motor = string;
       }
    }
    

    Pull Up 重構(gòu)與 Push Down 幾乎相同,當(dāng)然 Pull Up 是將類成員從一個(gè)類中移到其父類中,而不是子類中。如果您稍后改變主意,決定還是把 motor 移回到 Vehicle 類中,那么您也許就會(huì)用到這種重構(gòu)。同樣需要提醒您,一定要確認(rèn)您是否選擇了所有必需的成員。

    Automobile 類中具有成員 motor,這意味著您如果創(chuàng)建另一個(gè)子類,比方說 Bus ,您就還需要將 motor (及其相關(guān)方法)加入到 Bus 類中。有一種方法可以表示這種關(guān)系,即創(chuàng)建一個(gè)名為 Motorized 的接口, AutomobileBus 都實(shí)現(xiàn)這個(gè)接口,但是 RowBoat 不實(shí)現(xiàn)。

    創(chuàng)建 Motorized 接口最簡(jiǎn)單的方法是在 Automobile 上使用 Extract Interface 重構(gòu)。為此,您可以在 Outline 視圖中選擇 Automobile ,然后從菜單中選擇 Refactor > Extract Interface。您可以在彈出的對(duì)話框中選擇您希望在接口中包含哪些方法,如圖4所示。

    圖 4. 提取 Motorized 接口
    Motorized interface

    點(diǎn)擊 OK 之后,接口就創(chuàng)建好了,如清單8所示。


    清單 8. Motorized 接口
    
    public interface Motorized
    {
       public abstract String getMotor();
       public abstract void setMotor(String string);
    }
    

    同時(shí), Automobile 的類聲明也變成了下面的樣子:

    
    public class Automobile extends Vehicle implements Motorized
    

    使用父類

    本重構(gòu)工具類型中最后一個(gè)是 User Supertyp Where Possible。想象一個(gè)用來管理汽車細(xì)帳的應(yīng)用程序。它自始至終都使用 Automobile 類型的對(duì)象。如果您想處理所有類型的交通工具,那么您就可以用這種重構(gòu)將所有對(duì) Automobile 的引用都變成對(duì) Vehicle 的引用(參看圖5)。如果您在代碼中用 instanceof 操作執(zhí)行了任何類型檢查的話,您將需要決定在這些地方適用的是原先的類還是父類,然后選中第一個(gè)選項(xiàng)“Use the selected supertype in 'instanceof' expressions”。

    圖 5. 將 Automobile 改成其父類 Vehicle
    Supertype

    使用父類的需求在 Java 語言中經(jīng)常出現(xiàn),特別是在使用了 Factory Method 模式的情況下。這種模式的典型實(shí)現(xiàn)方式是創(chuàng)建一個(gè)抽象類,其中具有靜態(tài)方法 create() ,這個(gè)方法返回的是實(shí)現(xiàn)了這個(gè)抽象類的一個(gè)具體對(duì)象。如果需創(chuàng)建的具體對(duì)象的類型依賴于實(shí)現(xiàn)的細(xì)節(jié),而調(diào)用類對(duì)實(shí)現(xiàn)細(xì)節(jié)并不感興趣的情況下,可以使用這一模式。



    回頁首


    改變類內(nèi)部的代碼

    最大一類重構(gòu)是實(shí)現(xiàn)了類內(nèi)部代碼重組的重構(gòu)方法。在所有的重構(gòu)方法中,只有這類方法允許您引入或者移除中間變量,根據(jù)原有方法中的部分代碼創(chuàng)建新方法,以及為屬性創(chuàng)建 getter 和 setter 方法。

    提取與內(nèi)嵌

    有一些重構(gòu)方法是以 Extract 這個(gè)詞開頭的:Extract Method、Extract Local Variable 以及Extract Constants。第一個(gè) Extract Method 的意思您可能已經(jīng)猜到了,它根據(jù)您選中的代碼創(chuàng)建新的方法。我們以清單8中那個(gè)類的 main() 方法為例。它首先取得命令行選項(xiàng)的值,如果有以 -D 開頭的選項(xiàng),就將其以名-值對(duì)的形式存儲(chǔ)在一個(gè) Properties 對(duì)象中。


    清單 8. main()
    
    import java.util.Properties;
    import java.util.StringTokenizer;
    public class StartApp
    {
       public static void main(String[] args)
       {
          Properties props = new Properties();
          for (int i= 0; i < args.length; i++)
          {
             if(args[i].startsWith("-D"))
             {
               String s = args[i].substring(2);
               StringTokenizer st = new StringTokenizer(s, "=");
                if(st.countTokens() == 2)
                {
                  props.setProperty(st.nextToken(), st.nextToken());
                }
             }
          }
          //continue...
       }
    }
    

    將一部分代碼從一個(gè)方法中取出并放進(jìn)另一個(gè)方法中的原因主要有兩種。第一種原因是這個(gè)方法太長(zhǎng),并且完成了兩個(gè)以上邏輯上截然不同的操作。(我們不知道上面那個(gè) main() 方法還要處理哪些東西,但是從現(xiàn)在掌握的證據(jù)來看,這不是從其中提取出一個(gè)方法的理由。)另一種原因是有一段邏輯上清晰的代碼,這段代碼可以被其他方法重用。比方說在某些時(shí)候,您發(fā)現(xiàn)自己在很多不同的方法中都重復(fù)編寫了相同的幾行代碼。那就有可能是需要重構(gòu)的原因了,不過除非真的需要重用這部分代碼,否則您很可能并不會(huì)執(zhí)行重構(gòu)。

    假設(shè)您還需要在另外一個(gè)地方解析名-值對(duì),并將其放在 Properties 對(duì)象中,那么您可以將包含 StringTokenizer 聲明和下面的 if 語句的這段代碼抽取出來。為此,您可以高亮選中這段代碼,然后從菜單中選擇 Refactor > Extract Method。您需要輸入方法名稱,這里輸入 addProperty ,然后驗(yàn)證這個(gè)方法的兩個(gè)參數(shù), Properties prop Strings 。清單9顯示由 Eclipse 提取了 addProp() 方法之后類的情況。


    清單 9. 提取出來的 addProp()
    
    import java.util.Properties;
    import java.util.StringTokenizer;
    public class Extract
    {
       public static void main(String[] args)
       {
          Properties props = new Properties();
          for (int i = 0; i < args.length; i++)
          {
             if (args[i].startsWith("-D"))
             {
                String s = args[i].substring(2);
                addProp(props, s);
             }
          }
       }
       private static void addProp(Properties props, String s)
       {
          StringTokenizer st = new StringTokenizer(s, "=");
          if (st.countTokens() == 2)
          {
             props.setProperty(st.nextToken(), st.nextToken());
          }
       }
    }
    

    Extract Local Variable 重構(gòu)取出一段被直接使用的表達(dá)式,然后將這個(gè)表達(dá)式首先賦值給一個(gè)局部變量。然后在原先使用那個(gè)表達(dá)式的地方使用這個(gè)變量。比方說,在上面的方法中,您可以高亮選中對(duì) st.nextToken() 的第一次調(diào)用,然后選擇 Refactor > Extract Local Variable。您將被提示輸入一個(gè)變量名稱,這里輸入 key 。請(qǐng)注意,這里有一個(gè)將被選中表達(dá)式所有出現(xiàn)的地方都替換成新變量的引用的選項(xiàng)。這個(gè)選項(xiàng)通常是適用的,但是對(duì)這里的 nextToken() 方法不適用,因?yàn)檫@個(gè)方法(顯然)在每一次調(diào)用的時(shí)候都返回不同的值。確認(rèn)這個(gè)選項(xiàng)未被選中。參見圖6。

    圖 6. 不全部替換所選的表達(dá)式
    Extract variable

    接下來,在第二次調(diào)用 st.nextToken() 的地方重復(fù)進(jìn)行重構(gòu),這一次調(diào)用的是一個(gè)新的局部變量 value 。清單10顯示了這兩次重構(gòu)之后代碼的情形。


    清單 10. 重構(gòu)之后的代碼
    
    private static void addProp(Properties props, String s)
       {
         StringTokenizer st = new StringTokenizer(s, "=");
          if(st.countTokens() == 2)
          {
             String key = st.nextToken();
             String value = st.nextToken();
            props.setProperty(key, value);
          }
       }
    

    用這種方式引入變量有幾點(diǎn)好處。首先,通過為表達(dá)式提供有意義的名稱,可以使得代碼執(zhí)行的任務(wù)更加清晰。第二,代碼調(diào)試變得更容易,因?yàn)槲覀兛梢院苋菀椎貦z查表達(dá)式返回的值。最后,在可以用一個(gè)變量替換同一表達(dá)式的多個(gè)實(shí)例的情況下,效率將大大提高。

    Extract Constant 與 Extract Local Variable 相似,但是您必須選擇靜態(tài)常量表達(dá)式,重構(gòu)工具將會(huì)把它轉(zhuǎn)換成靜態(tài)的 final 常量。這在將硬編碼的數(shù)字和字符串從代碼中去除的時(shí)候非常有用。比方說,在上面的代碼中我們用“-D”這一命令行選項(xiàng)來定義名-值對(duì)。先將“-D”高亮選中,選擇 Refactor > Extract Constant,然后輸入 DEFINE 作為常量的名稱。重構(gòu)之后的代碼如清單11所示:


    清單 11. 重構(gòu)之后的代碼
    
    public class Extract
    {
       private static final String DEFINE = "-D";
       public static void main(String[] args)
       {
          Properties props = new Properties();
          for (int i = 0; i < args.length; i++)
          {
             if (args[i].startsWith(DEFINE))
             {
                String s = args[i].substring(2);
                addProp(props, s);
             }
          }
       }
       // ...
    

    對(duì)于每一種 Extract... 類的重構(gòu),都存在對(duì)應(yīng)的 Inline... 重構(gòu),執(zhí)行與之相反的操作。比方說,如果您高亮選中上面代碼中的變量 s,選擇 Refactor > Inline...,然后點(diǎn)擊 OK,Eclipse 就會(huì)在調(diào)用 addProp() 的時(shí)候直接使用 args[i].substring(2) 這個(gè)表達(dá)式,如下所示:

            if(args[i].startsWith(DEFINE))
             {
                addProp(props,args[i].substring(2));
             }

    這樣比使用臨時(shí)變量效率更高,代碼也變得更加簡(jiǎn)要,至于這樣的代碼是易讀還是含混,就取決于您的觀點(diǎn)了。不過一般說來,這樣的內(nèi)嵌重構(gòu)沒什么值得推薦的地方。

    您可以按照用內(nèi)嵌表達(dá)式替換變量的相同方法,高亮選中方法名,或者靜態(tài) final 常量,然后從菜單中選擇 Refactor > Inline...,Eclipse 就會(huì)用方法的代碼替換方法調(diào)用,或者用常量的值替換對(duì)常量的引用。

    封裝屬性

    通常我們認(rèn)為將對(duì)象的內(nèi)部結(jié)構(gòu)暴露出來是一種不好的做法。這也正是 Vehicle 類及其子類都具有 private 或者 protected 屬性,而用 public setter 和 getter 方法來訪問屬性的原因。這些方法可以用兩種不同的方式自動(dòng)生成。

    第一種生成這些方法的方式是使用 Source > Generate Getter and Setter 菜單。這將會(huì)顯示一個(gè)對(duì)話框,其中包含所有尚未存在的 getter 和 setter 方法。不過因?yàn)檫@種方式?jīng)]有用新方法更新對(duì)這些屬性的引用,所以并不算是重構(gòu);必要的時(shí)候,您必須自己完成更新引用的工作。這種方式可以節(jié)約很多時(shí)間,但是最好是在一開始創(chuàng)建類的時(shí)候,或者是向類中加入新屬性的時(shí)候使用,因?yàn)檫@些時(shí)候還不存在對(duì)屬性的引用,所以不需要再修改其他代碼。

    第二種生成 getter 和 setter 方法的方式是選中某個(gè)屬性,然后從菜單中選擇 Refactor > Encapsulate Field。這種方式一次只能為一個(gè)屬性生成 getter 和 setter 方法,不過它與 Source > Generate Getter and Setter 相反,可以將對(duì)這個(gè)屬性的引用改變成對(duì)新方法的調(diào)用。

    例如,我們可以先創(chuàng)建一個(gè)新的簡(jiǎn)版 Automobile 類,如清單12所示。


    清單 12. 簡(jiǎn)單的 Automobile 類
    
    public class Automobile extends Vehicle
    {
       public String make;
       public String model;
    }
    

    接下來,創(chuàng)建一個(gè)類實(shí)例化了 Automobile 的類,并直接訪問 make 屬性,如清單13所示。


    清單 13. 實(shí)例化 Automobile
    
    public class AutomobileTest
    {
       public void race()
       {
          Automobilecar1 = new Automobile();
          car1.make= "Austin Healy";
          car1.model= "Sprite";
          // ...
       }
    }

    現(xiàn)在封裝 make 屬性。先高亮選中屬性名稱,然后選擇 Refactor > Encapsulate Field。在彈出的對(duì)話框中輸入 getter 和 setter 方法的名稱——如您所料,缺省的方法名稱分別是 getMake() 和 setMake()。您也可以選擇與這個(gè)屬性處在同一個(gè)類中的方法是繼續(xù)直接訪問該屬性,還是像其他類那樣改用這些訪問方法。(有一些人非常傾向于使用這兩種方式的某一種,不過碰巧在這種情況下您選擇哪一種方式都沒有區(qū)別,因?yàn)?Automobile 中沒有對(duì) make 屬性的引用。)

    圖7. 封裝屬性
    Encapsulating a field

    點(diǎn)擊 OK之后, Automobile 類中的 make 屬性就變成了私有屬性,也同時(shí)具有了 getMake() setMake() 方法。

    >
    清單 14. 經(jīng)過重構(gòu)的 Automobile 類
    public class Automobile extends Vehicle
    {
       private String make;
       public String model;
    
       public void setMake(String make)
       {
          this.make = make;
       }
    
       public String getMake()
       {
          return make;
       }
    }
    

    AutomobileTest 類也要進(jìn)行更新,以便使用新的訪問方法,如清單15所示。


    >清單 15. AutomobileTest 類
    
    public class AutomobileTest
    {
       public void race()
       {
          Automobilecar1 = new Automobile();
          car1.setMake("Austin Healy");
          car1.model= "Sprite";
          // ...
       }
    }

    改變方法的簽名

    本文介紹的最后一個(gè)重構(gòu)方法也是最難以使用的方法:Change Method Signature(改變方法的簽名)。這種方法的功能顯而易見——改變方法的參數(shù)、可見性以及返回值的類型。而進(jìn)行這樣的改變對(duì)于調(diào)用這個(gè)方法的其他方法或者代碼會(huì)產(chǎn)生什么影響,就不是那么顯而易見了。這么也沒有什么魔方。如果代碼的改變?cè)诒恢貥?gòu)的方法內(nèi)部引發(fā)了問題——變量未定義,或者類型不匹配——重構(gòu)操作將對(duì)這些問題進(jìn)行標(biāo)記。您可以選擇是接受重構(gòu),稍后改正這些問題,還是取消重構(gòu)。如果這種重構(gòu)在其他的方法中引發(fā)問題,就直接忽略這些問題,您必須在重構(gòu)之后親自修改。

    為澄清這一點(diǎn),考慮清單16中列出的類和方法。


    清單 16. MethodSigExample 類
    
    public class MethodSigExample
    {
       public int test(String s, int i)
       {
          int x = i + s.length();
          return x;
       }
    }
    

    上面這個(gè)類中的 test() 方法被另一個(gè)類中的方法調(diào)用,如清單17所示。


    清單 17. callTest 方法
    
    public void callTest()
       {
         MethodSigExample eg = new MethodSigExample();
         int r = eg.test("hello", 10);
       }

    在第一個(gè)類中高亮選中 test ,然后選擇 Refactor > Change Method Signature。您將看到如圖8所示的對(duì)話框。

    圖 8. Change Method Signature 選項(xiàng)
    Change Method Signature options

    第一個(gè)選項(xiàng)是改變?cè)摲椒ǖ目梢娦?。在本例中,將其改變?yōu)?protected 或者 private,這樣第二個(gè)類的 callTest() 方法就不能訪問這個(gè)方法了。(如果這兩個(gè)類在不同的包中,將訪問方法設(shè)為缺省值也會(huì)引起這樣的問題。) Eclipse 在進(jìn)行重構(gòu)的時(shí)候不會(huì)將這些問題標(biāo)出,您只有自己選擇適當(dāng)?shù)闹怠?

    下面一個(gè)選項(xiàng)是改變返回值類型。如果將返回值改為 float ,這不會(huì)被標(biāo)記成錯(cuò)誤,因?yàn)?test() 方法返回語句中的 int 會(huì)自動(dòng)轉(zhuǎn)換成 float 。即便如此,在第二個(gè)類的 callTest() 方法中也會(huì)引起問題,因?yàn)?float 不能轉(zhuǎn)換成 int 。您需要將 test() 的返回值改為 int ,或者是將 callTest() 中的 r 改為 float 。

    如果將第一個(gè)參數(shù)的類型從 String 變成 int ,那么也得考慮相同的問題。在重構(gòu)的過程中這些問題將會(huì)被標(biāo)出,因?yàn)樗鼈儠?huì)在被重構(gòu)的方法內(nèi)部引起問題: int 不具有方法 length() 。然而如果將其變成 StringBuffer ,問題就不會(huì)標(biāo)記出來,因?yàn)?StringBuffer 的確具有方法 length() 。當(dāng)然這會(huì)在 callTest() 方法中引起問題,因?yàn)樗谡{(diào)用 test() 的時(shí)候還是把一個(gè) String 傳遞進(jìn)去了。

    前面提到過,在重構(gòu)引發(fā)了問題的情況下,不管問題是否被標(biāo)出,您都可以一個(gè)一個(gè)地修正這些問題,以繼續(xù)下去。還有一種方法,就是先行修改這些錯(cuò)誤。如果您打算刪除不再需要的參數(shù) i ,那么可以先從要進(jìn)行重構(gòu)的方法中刪除對(duì)它的引用。這樣刪除參數(shù)的過程就更加順利了。

    最后一件需要解釋的事情是 Default Value 選項(xiàng)。這一選項(xiàng)值僅適用于將參數(shù)加入方法簽名中的情況。比方說,如果我們加入了一個(gè)類型為 String 的參數(shù),參數(shù)名為 n ,其缺省值為 world ,那么在 callTest() 方法中調(diào)用 test() 的代碼就變成下面的樣子:

          
             public void callTest()
       {
          MethodSigExample eg = new MethodSigExample();
          int r = eg.test("hello", 10, "world");
       }
    

    在這場(chǎng)有關(guān) Change Method Signature 重構(gòu)的看似可怕的討論中,我們并沒有隱藏其中的問題,但卻一直沒有提到,這種重構(gòu)其實(shí)是非常強(qiáng)大的工具,它可以節(jié)約很多時(shí)間,通常您必須進(jìn)行仔細(xì)的計(jì)劃才能成功地使用它。



    回頁首


    結(jié)束語

    Eclipse 提供的工具使重構(gòu)變得簡(jiǎn)單,熟悉這些工具將有助于您提高效率。敏捷開發(fā)方法采用迭代方式增加程序特性,因此需要依賴于重構(gòu)技術(shù)來改變和擴(kuò)展程序的設(shè)計(jì)。但即便您并沒有使用要求進(jìn)行正式重構(gòu)的方法,Eclipse 的重構(gòu)工具還是可以在進(jìn)行一般的代碼修改時(shí)提供節(jié)約時(shí)間的方法。如果您花些時(shí)間熟悉這些工具,那么當(dāng)出現(xiàn)可以利用它們的情況時(shí),您就能意識(shí)到所花費(fèi)的時(shí)間是值得的。



    回頁首


    參考資料

    • 您可以參閱本文在 developerWorks 全球站點(diǎn)上的 英文原文.

    • 有關(guān)重構(gòu)的核心著作是 Refactoring: Improving the Design of Existing Code, 作者 Martin Fowler、Kent Beck、John Brant、William Opdyke 和 Don Roberts(Addison-Wesley,1999年)。

    • 重構(gòu)是一種正在發(fā)展的方法,在 Eclipse In Action: A Guide for Java Developers (Manning, 2003年)一書中,作者 David Gallardo,Ed Burnette 以及 Robert McGovern 從在 Eclipse 中設(shè)計(jì)和開發(fā)項(xiàng)目的角度討論了這一話題。

    • 模式(如本文中提到的 Factory Method 模式)是理解和討論面向?qū)ο笤O(shè)計(jì)的重要工具。這方面的經(jīng)典著作是 Design Patterns: Elements of Reusable Object-Oriented Software,作者為 Erich Gamma、Richard Helm、Ralph Johnson 和 John Vlissides (Addison-Wesley,1995年)。

    • Design Patterns 中的例子是用 C++ 寫成的,這對(duì)于 Java 程序員是不小的障礙;Mark Grand 所著的 Patterns in Java, Volume One: A Catalog of Reusable Design Patterns Illustrated with UML(Wiley,1998年)將模式翻譯成了 Java 語言。

    • 有關(guān)敏捷編程的一個(gè)變種,請(qǐng)參看 Kent Beck 所著的 Extreme Programming Explained: Embrace Change(Addison-Wesley,1999年)
    Web 站點(diǎn) developerWorks 上的文章與教程

    回頁首


    關(guān)于作者

    David Gallardo 是 Studio B 上的一名作家,他是一名獨(dú)立軟件顧問和作家,專長(zhǎng)為軟件國(guó)際化、Java Web 應(yīng)用程序和數(shù)據(jù)庫開發(fā)。他成為專業(yè)軟件工程師已經(jīng)有十五年了,他擁有許多操作系統(tǒng)、編程語言和網(wǎng)絡(luò)協(xié)議的經(jīng)驗(yàn)。他最近在一家 BtoB 電子商務(wù)公司 TradeAccess, Inc 領(lǐng)導(dǎo)數(shù)據(jù)庫和國(guó)際化開發(fā)。在這之前,他是 Lotus Development Corporation 的 International Product Development 組中的高級(jí)工程師,負(fù)責(zé)為 Lotus 產(chǎn)品(包括 Domino)提供 Unicode 和國(guó)際語言支持的跨平臺(tái)庫的開發(fā)。David 是 Eclipse In Action: A Guide for Java Developers(2003年)一書的合著者??梢酝ㄟ^ david@gallardo.org 與 David 聯(lián)系。

    posted @ 2006-01-17 15:28 只牽這只狗 閱讀(333) | 評(píng)論 (0)編輯 收藏

    原來自己的生日已經(jīng)過了......不知不覺的過了...........
    posted @ 2006-01-10 09:29 只牽這只狗 閱讀(200) | 評(píng)論 (0)編輯 收藏

    男人25歲前不會(huì)明白的道理

        

      1、男人是社會(huì)的主體,不管你信或不信。所以男人應(yīng)該有種責(zé)任感。
       
      2、25歲之前,請(qǐng)記得,愛情通常是假的,或者不是你所想象的那樣純潔和永遠(yuǎn)。如果你過了25歲,那么你應(yīng)該懂得這個(gè)道理。
       
      3、吃飯7成飽最舒服。對(duì)待女友最多也請(qǐng)你保持在7成。
       
      4、30歲之前請(qǐng)愛惜自己的身體,前30年你找病,后30年病找你。如果你過了30歲,你自然也會(huì)懂得這個(gè)道理。
       
      5、事業(yè)遠(yuǎn)比愛情重要。如果說事業(yè)都不能永恒,那么愛情只能算是曇花一現(xiàn)。
       
      6、不要輕易接受追求你的女孩。女追男隔層紗,如果你很容易就陷進(jìn)去,你會(huì)發(fā)現(xiàn)你會(huì)錯(cuò)過很多東西,失去很多東西。
       
      7、請(qǐng)你相信,能用錢解決的問題,都不是問題。如果你認(rèn)為錢索王道,有錢有女人,沒錢沒女人,那么,女人不是問題。
       
      8、請(qǐng)永遠(yuǎn)積極向上。每個(gè)男人都有他可愛的地方,但是不可愛的地方只有:不積極面對(duì)生活。
       
      9、不要連續(xù)2次讓同一個(gè)女人受到傷害。好馬不吃回頭草是有道理的。如果認(rèn)真考慮過該分手,那么請(qǐng)不要做任何舍不得的行動(dòng)。
       
      10、如果你和你前女友能做朋友,那么你要問自己:為什么?如果分手后還是朋友,那么只有2個(gè)可能:你們當(dāng)初都只是玩玩而已,沒付出彼此最真的感情;或者:必定有個(gè)人是在默默的付出無怨無悔!
       
      11、永遠(yuǎn)不要太相信女人在戀愛時(shí)的甜言蜜語。都說女人愛聽甜言蜜語,其實(shí),男人更喜歡。
       
      12、請(qǐng)不要為自己的相貌或者身高過分擔(dān)心和自卑。人是動(dòng)物,但是區(qū)別于動(dòng)物。先天條件并不是阻擋你好好生活的借口。人的心靈遠(yuǎn)勝于相貌,請(qǐng)相信這點(diǎn)。如果有人以相貌取人,那么你也沒必要太在意。因?yàn)樗麖哪撤N意義來講,只是只動(dòng)物,你會(huì)跟動(dòng)物慪氣嗎?
       
      13、失戀時(shí),只有2種可能,要么你愛她她不愛你,或者相反。那么,當(dāng)你愛的人不再愛你,或者從來沒愛過你時(shí),你沒有遺憾,因?yàn)槟闶サ闹皇且粋€(gè)不愛你的人。
       
      14、請(qǐng)不要欺騙善良的女孩。這個(gè)世界上善良的女孩太少。
       
      15、不能偏激的認(rèn)為金錢萬能,至少,金錢治不好艾滋病。
       
      16、請(qǐng)一定要有自信。你就是一道風(fēng)景,沒必要在別人風(fēng)景里面仰視。
       
      17、受到再大的打擊,只要生命還在,請(qǐng)相信每天的太陽都是新的。
       
      18、愛情永遠(yuǎn)不可能是天平。你想在愛情里幸福就要舍得傷心。
       
      19、如果你喜歡一個(gè)她認(rèn)為別人應(yīng)該對(duì)她好的MM,請(qǐng)盡早放棄。沒有人是應(yīng)該對(duì)一個(gè)人好的。如果她不明白這個(gè)道理,也就是她根本不懂得珍惜。
       
      20、不要因?yàn)榧拍罢摇盙F,寂寞的男人請(qǐng)要學(xué)會(huì)品味寂寞。請(qǐng)記?。杭词辜拍?,遠(yuǎn)方黑暗的夜空下,一定有人和你一樣,寂寞的人不同,仰望的星空卻是唯一。
       
      21、任何事沒有永遠(yuǎn),也別問怎樣才能永遠(yuǎn)。生活有很多無奈,請(qǐng)盡量充實(shí)自己,充實(shí)生活。請(qǐng)善待生活。
       
      End、男人有很多無奈,生活很累,但是因?yàn)樯畈庞幸饬x。當(dāng)你以為你一無所有時(shí),你至少還有時(shí)間,時(shí)間能撫平一切創(chuàng)傷。所以請(qǐng)不要流淚。

    posted @ 2006-01-10 09:12 只牽這只狗 閱讀(234) | 評(píng)論 (0)編輯 收藏

    也許明天會(huì)更好.......

    posted @ 2006-01-10 08:51 只牽這只狗 閱讀(218) | 評(píng)論 (0)編輯 收藏

    摘要:

    雖然大部分開發(fā)人員在過去使用過XMLHttp或者使用Iframe來加載數(shù)據(jù),但僅到現(xiàn)在我們才看到傳統(tǒng)的開發(fā)人員和公司開始采用這些技術(shù)。就像新的編程語言或模型伴隨著更多的痛苦,開發(fā)人員需要學(xué)習(xí)新的技巧及如何最好利用這些新技術(shù)。這篇文章講述了開發(fā)人員使用AJAX需要使用的工具和技術(shù)。

    文章工具

    作者:Andrew Thompson;xMatrix (他的blog:http://blog.matrix.org.cn/page/xMatrix)
    原文地址:http://www.javaworld.com/javaworld/jw-10-2005/jw-1017-ajax.html
    中文地址:http://www.matrix.org.cn/resource/article/44/44116_AJAX.html
    關(guān)鍵詞: AJAX

    AJAX開發(fā)者的最新工具和技術(shù)

    基于XML的異步JavaScript,簡(jiǎn)稱AJAX,是當(dāng)前Web創(chuàng)新(稱為Web2.0)中的一個(gè)王冠。感謝組成AJAX的各種技術(shù),Web應(yīng)用的交互如Flickr, Backpack和Google在這方面已經(jīng)有質(zhì)的飛躍。這個(gè)術(shù)語源自描述從基于網(wǎng)頁的Web應(yīng)用到基于數(shù)據(jù)的應(yīng)用的轉(zhuǎn)換。在基于數(shù)據(jù)的應(yīng)用中,用戶需求的數(shù)據(jù)如聯(lián)系人列表,可以從獨(dú)立于實(shí)際網(wǎng)頁的服務(wù)端取得并且可以被動(dòng)態(tài)地寫入網(wǎng)頁中,給緩慢的Web應(yīng)用體驗(yàn)著色使之像桌面應(yīng)用一樣。

    雖然大部分開發(fā)人員在過去使用過XMLHttp或者使用Iframe來加載數(shù)據(jù),但僅到現(xiàn)在我們才看到傳統(tǒng)的開發(fā)人員和公司開始采用這些技術(shù)。就像新的編程語言或模型伴隨著更多的痛苦,開發(fā)人員需要學(xué)習(xí)新的技巧及如何最好利用這些新技術(shù)。這篇文章講述了開發(fā)人員使用AJAX枰褂玫墓ぞ吆圖際酢?lt;br />
    AJAX模式
    許多重要的技術(shù)和AJAX開發(fā)模式可以從現(xiàn)有的知識(shí)中獲取。例如,在一個(gè)發(fā)送請(qǐng)求到服務(wù)端的應(yīng)用中,必須包含請(qǐng)求順序、優(yōu)先級(jí)、超時(shí)響應(yīng)、錯(cuò)誤處理及回調(diào),其中許多元素已經(jīng)在Web服務(wù)中包含了,就像現(xiàn)在的SOA。AJAX開發(fā)人員擁有一個(gè)完整的系統(tǒng)架構(gòu)知識(shí)。同時(shí),隨著技術(shù)的成熟還會(huì)有許多地方需要改進(jìn),特別是UI部分的易用性。

    AJAX開發(fā)與傳統(tǒng)的CS開發(fā)有很大的不同。這些不同引入了新的編程問題,最大的問題在于易用性。由于AJAX依賴瀏覽器的JavaScript和XML,瀏覽器的兼容性和支持的標(biāo)準(zhǔn)也變得和JavaScript的運(yùn)行時(shí)性能一樣重要了。這些問題中的大部分來源于瀏覽器、服務(wù)器和技術(shù)的組合,因此必須理解如何才能最好的使用這些技術(shù)。

    綜合各種變化的技術(shù)和強(qiáng)耦合的客戶服務(wù)端環(huán)境,AJAX提出了一種新的開發(fā)方式。AJAX開發(fā)人員必須理解傳統(tǒng)的MVC架構(gòu),這限制了應(yīng)用層次之間的邊界。同時(shí),開發(fā)人員還需要考慮CS環(huán)境的外部和使用AJAX技術(shù)來重定型MVC邊界。最重要的是,AJAX開發(fā)人員必須禁止以頁面集合的方式來考慮Web應(yīng)用而需要將其認(rèn)為是單個(gè)頁面。一旦UI設(shè)計(jì)與服務(wù)架構(gòu)之間的范圍被嚴(yán)格區(qū)分開來后,開發(fā)人員就需要更新和變化的技術(shù)集合了。


    時(shí)刻想著用戶
    AJAX的最大機(jī)遇在于用戶體驗(yàn)。在使應(yīng)用更快響應(yīng)和創(chuàng)新的過程中,定義Web應(yīng)用的規(guī)則正在被重寫;因此開發(fā)人員必須更注重用戶?,F(xiàn)在用戶已經(jīng)逐漸習(xí)慣如何使用Web應(yīng)用了。例如用戶通常希望每一次按鈕點(diǎn)擊會(huì)導(dǎo)致幾秒的延遲和屏幕刷新,但AJAX正在打破這種長(zhǎng)時(shí)間的狀況。因此用戶需要重新體驗(yàn)按鈕點(diǎn)擊的響應(yīng)了。

    可用性是AJAX另人激動(dòng)的地方而且已經(jīng)產(chǎn)生了幾種新穎的技術(shù)。其中最引人注目的是一種稱為“黃色隱出”的技術(shù),他在數(shù)據(jù)更新之前時(shí)將用戶界面變?yōu)辄S色,更新完成后立刻恢復(fù)原來的顏色。AJAX開發(fā)人員將用戶從Web應(yīng)用的負(fù)載中解放出來;小心地利用AJAX提供的豐富接口,不久桌面開發(fā)人員會(huì)發(fā)現(xiàn)AJAX是他們的方向。


    幾種工具和技術(shù)
    隨著AJAX迅速地引人注目起來,我想開發(fā)人員對(duì)這種技術(shù)的期待也迅速地增加。就像任何新技術(shù),AJAX的興旺也需要一整個(gè)開發(fā)工具/編程語言及相關(guān)技術(shù)系統(tǒng)來支撐。

    JavaScript
    如名字所示AJAX的概念中最重要而最被忽視的是他也是一種JavaScript編程語言。JavaScript是一種粘合劑使AJAX應(yīng)用的各部分集成在一起。在大部分時(shí)間,JavaScript通常被服務(wù)端開發(fā)人員認(rèn)為是一種企業(yè)級(jí)應(yīng)用不需要使用的東西應(yīng)該盡力避免。這種觀點(diǎn)來來自以前編寫JavaScript代碼的經(jīng)歷:繁雜而又易出錯(cuò)的語言。類似的,他也被認(rèn)為將應(yīng)用邏輯任意地散布在服務(wù)端和客戶端中,這使得問題很難被發(fā)現(xiàn)而且代碼很難重用。在AJAX中JavaScript主要被用來傳遞用戶界面上的數(shù)據(jù)到服務(wù)端并返回結(jié)果。XMLHttpRequest對(duì)象用來響應(yīng)通過HTTP傳遞的數(shù)據(jù),一旦數(shù)據(jù)返回到客戶端就可以立刻使用DOM將數(shù)據(jù)放到網(wǎng)面上。

    XMLHttpRequest
    XMLHttpRequest對(duì)象在大部分瀏覽器上已經(jīng)實(shí)現(xiàn)而且擁有一個(gè)簡(jiǎn)單的接口允許數(shù)據(jù)從客戶端傳遞到服務(wù)端,但并不會(huì)打斷用戶當(dāng)前的操作。使用XMLHttpRequest傳送的數(shù)據(jù)可以是任何格式,雖然從名字上建議是XML格式的數(shù)據(jù)。

    開發(fā)人員應(yīng)該已經(jīng)熟悉了許多其他XML相關(guān)的技術(shù)。XPath可以訪問XML文檔中的數(shù)據(jù),但理解XML DOM是必須的。類似的,XSLT是最簡(jiǎn)單而快速的從XML數(shù)據(jù)生成HTML或XML的方式。許多開發(fā)人員已經(jīng)熟悉Xpath和XSLT,因此AJAX選擇XML作為數(shù)據(jù)交換格式有意義的。XSLT可以被用在客戶端和服務(wù)端,他能夠減少大量的用JavaScript編寫的應(yīng)用邏輯。

    CSS
    為了正確的瀏覽AJAX應(yīng)用,CSS是一種AJAX開發(fā)人員所需要的重要武器。CSS提供了從內(nèi)容中分離應(yīng)用樣式和設(shè)計(jì)的機(jī)制。雖然CSS在AJAX應(yīng)用中扮演至關(guān)重要的角色,但他也是構(gòu)建創(chuàng)建跨瀏覽器應(yīng)用的一大阻礙,因?yàn)椴煌臑g覽器廠商支持各種不同的CSS級(jí)別。

    服務(wù)器端
    但不像在客戶端,在服務(wù)端AJAX應(yīng)用還是使用建立在如Java,.Net和PHP語言基礎(chǔ)上機(jī)制;并沒有改變這個(gè)領(lǐng)域中的主要方式。
    既然如此,我們對(duì)Ruby on Rails框架的興趣也就迅速增加了。在一年多前,Ruby on Rails已經(jīng)吸引了大量開發(fā)人員基于其強(qiáng)大功能來構(gòu)建Web和AJAX應(yīng)用。雖然目前還有很多快速應(yīng)用開發(fā)工具存在,Ruby on Rails看起來已經(jīng)儲(chǔ)備了簡(jiǎn)化構(gòu)建AJAX應(yīng)用的能力。

    開發(fā)工具
    在實(shí)際構(gòu)建AJAX應(yīng)用中,你需要的不只是文本編輯器。既然是JavaScript非編譯的,他可以容易地編寫和運(yùn)行在瀏覽器中;然而,許多工具提供了有用的擴(kuò)展如語法高亮和智能完成。

    不同的IDE提供了對(duì)JavaScript支持的不同等級(jí)。來自JetBrains的IntelliJ IDEA是一個(gè)用來JavaScript開發(fā)的更好的IDE,雖然許多開發(fā)人員也喜歡Microsoft’s Visual Studio產(chǎn)品(允諾會(huì)在最新的版本中改善對(duì)AJAX的支持)。Eclipse包含了兩個(gè)免費(fèi)的JavaScript編輯器插件和一個(gè)商業(yè)的來自ActiveStat的Komodo IDE。

    另一個(gè)JavaScript和AJAX開發(fā)中的問題是調(diào)試?yán)щy。不同的瀏覽器提供不同的通常是隱藏的運(yùn)行時(shí)錯(cuò)誤信息,而JavaScript的缺陷如雙重變量賦值(通常是由于缺少數(shù)據(jù)類型)使得調(diào)試更加困難。在AJAX的開發(fā)中,調(diào)試就更復(fù)雜了,因?yàn)槠湫枰獦?biāo)識(shí)究竟是客戶端還是服務(wù)端產(chǎn)生的錯(cuò)誤。在過去,JavaScript調(diào)試的方法是刪除所有代碼然后一行行的增加直到錯(cuò)誤出現(xiàn)?,F(xiàn)在,更多開發(fā)人員回到為IE準(zhǔn)備的Microsoft Script Debugger和為Mozilla瀏覽器準(zhǔn)備的Venkman。


    瀏覽器兼容性
    JavaScript編程的最大問題來自不同的瀏覽器對(duì)各種技術(shù)和標(biāo)準(zhǔn)的支持。構(gòu)建一個(gè)運(yùn)行在不同瀏覽器(如IE和火狐)是一個(gè)困難的任務(wù)。因此幾種AJAX JavaScript框架或者生成基于服務(wù)端邏輯或標(biāo)記庫的JavaScript,或者提供符合跨瀏覽器AJAX開發(fā)的客戶端JavaScript庫。一些流行的框架包括:AJAX.Net, Backbase, Bitkraft, Django, DOJO, DWR, MochiKit, Prototype, Rico, Sajax, Sarissa, and Script.aculo.us.

    這些框架給開發(fā)人員更多的空間使得他們不需要擔(dān)心跨瀏覽器的問題。雖然這些框架提升了開發(fā)人員構(gòu)建應(yīng)用的能力,但由于廠商已經(jīng)開發(fā)了更細(xì)節(jié)的用戶界面的打包組件解決方案,因此在AJAX組件市場(chǎng)中需要考慮一些其他因素。例如提供通用用戶界面的組件如組合框和數(shù)據(jù)柵格的幾個(gè)廠商,都可以被用來在應(yīng)用中創(chuàng)建良好的通過類似電子數(shù)據(jù)表方式來查看和編輯數(shù)據(jù)的體驗(yàn)。但這些組件不僅是封裝了組件的用戶界面而且包括與服務(wù)端數(shù)據(jù)的通訊方式,這些組件通常使用基于標(biāo)記方式來實(shí)現(xiàn)如ASP.Net或JSF控件。


    展望
    最近IE和火狐之間的瀏覽器之爭(zhēng)變得火熱起來,因此AJAX開發(fā)人員需要足夠敏捷的作出反應(yīng)。關(guān)鍵點(diǎn)在一些問題如CSS或XML,雖然各種瀏覽器形成采用最新標(biāo)準(zhǔn)的不同陣營(yíng)(如Mozilla擁抱SVG和E4X標(biāo)準(zhǔn)及在最新火狐BETA版本中使用XUL,而微軟使用自己的XAML技術(shù))。所有這些技術(shù)代表當(dāng)前AJAX主流JavaScript和XML的市場(chǎng)方向改變。
    總的來說,AJAX開發(fā)人員必須盡快地跟進(jìn)最新的技術(shù)并利用高產(chǎn)的工具集。成功的AJAX開發(fā)人員還需要留心他們的使用者以避免將任何問題擴(kuò)大化。并且AJAX開發(fā)人員還需要持續(xù)地創(chuàng)新來創(chuàng)建增強(qiáng)Web應(yīng)用易用性的新方法。


    作者
    Dave Johnson是加拿大Vancouver一家軟件咨詢公司eBusiness Applications創(chuàng)始人和傳道者,擁有七年以上的XML相關(guān)工作經(jīng)驗(yàn)。


    Resources
    ? AJAX開發(fā)人員的編譯模式:http://www.ajaxpatterns.org
    ?  XMLHttpRequest教程:“動(dòng)態(tài)網(wǎng)頁接口”:http://www.xml.com/pub/a/2005/02/09/xml-http-request.html
    ? JavaScript性能基準(zhǔn):http://blogs.ebusiness-apps.com/dave/?p=14
    ? AJAX資源:http://www.ajaxmatters.com
    ? JavaScript規(guī)范:http://www.ecma-international.org/publications/standards/Ecma-262.htm
    ? 介紹JavaScript對(duì)象標(biāo)識(shí):http://www.crockford.com/JSON/index.html
    ?  Mozilla 的Venkman JavaScript調(diào)試器:http://www.mozilla.org/projects/venkman/
    ?  XML DOM參考:http://msdn.microsoft.com/library/default.asp?url=/library/en-us/
    xmlsdk/html/e9da2722-7879-4e48-869c-7f16714e2824.asp
    ? Microsoft Dynamic HTML reference: http://msdn.microsoft.com/library/default.asp?url=/
    workshop/author/dhtml/reference/dhtml_reference_entry.asp
    ? Gecko DOM Reference: http://www.mozilla.org/docs/dom/domref/
    ? "“移植IE應(yīng)用到Mozilla”
    http://www-128.ibm.com/developerworks/web/library/wa-ie2mozgd/
    ? Mozilla XUL reference:
    http://www.xulplanet.com/
    ? Microsoft XAML reference:
    http://windowssdk.msdn.microsoft.com/library/default.asp?url=/library/
    en-us/wcp_conceptual/html/0ff5f36e-dd84-44d1-aa3e-5bb4f147b169.asp?frame=true
    ? James Jesses Garret introduced the term AJAX in his article "AJAX: A New Approach to Web Applications," (Adaptive Path, February 2005): “AJAX:新的網(wǎng)頁應(yīng)用開發(fā)方式”
    http://www.adaptivepath.com/publications/essays/archives/000385.php
    ? JetBrains IntelliJ IDEA:
    http://www.jetbrains.com/
    ? Microsoft Visual Studio:
    http://msdn.microsoft.com/vstudio/
    ? JSEditor:
    http://jseditor.sourceforge.net/
    ? JSEclipse:
    http://www.interaktonline.com/Products/Eclipse/JSEclipse/Overview/
    ? ActiveState Komodo:
    http://www.activestate.com/Products/Komodo/
    ? XHTML:
    http://www.w3.org/TR/xhtml1/
    ? Document Object Model:
    http://www.w3.org/DOM/
    ? Cascading Style Sheets:
    http://www.w3.org/Style/CSS/
    ? Extensible Stylesheet Language:
    http://www.w3.org/Style/XSL/
    ? XForms:
    http://www.w3.org/MarkUp/Forms/
    ? Scaling Vector Graphics:
    http://www.w3.org/Graphics/SVG/
    ? XPath:
    http://www.w3.org/TR/xpath
    ? AJAX.Net:
    http://ajax.schwarz-interactive.de/csharpsample/default.aspx
    ? Backbase:
    http://www.backbase.com
    ? Bitkraft:
    http://www.tiggrbitz.com/
    ? Django:
    http://www.djangoproject.com/
    ? Dojo:
    http://www.dojotoolkit.org/
    ? DWR (Direct Web Reporting):
    http://getahead.ltd.uk/dwr/
    ? MochiKit:
    http://mochikit.com/
    ? Prototype:
    http://prototype.conio.net/
    ? Rico:
    http://openrico.org/rico/home.page
    ? Sajax:
    http://www.modernmethod.com/sajax/
    ? Sarissa:
    http://sarissa.sourceforge.net/doc/
    ? Script.aculo.us:
    http://script.aculo.us/
    ? Ruby on Rails:
    http://www.rubyonrails.org/
    ? For more on AJAX and DWR, read "AJAX Made Simple with DWR," Cloves Carneiro Jr. (JavaWorld, June 2005): 關(guān)于AJAX和DWR,請(qǐng)閱讀“AJAX使用DWR更簡(jiǎn)單”
    http://www.javaworld.com/javaworld/jw-06-2005/jw-0620-dwr.html
    ? For more articles on Java development tools, browse the Development Tools section of JavaWorld’s Topical Index: 更多Java開發(fā)工具的文章,請(qǐng)瀏覽JavaWorld的開發(fā)工具部分索引頁
    http://www.javaworld.com/channel_content/jw-tools-index.shtml
    ? For more articles on XML, browse the Java and XML section of JavaWorld’s Topical Index: 更多XML的文章,請(qǐng)瀏覽JavaWorld的Java和XML部分索引頁
    http://www.javaworld.com/channel_content/jw-xml-index.shtml
    ? For more articles on UI design, browse the User Interface Design section of JavaWorld’s Topical Index: 更多UI設(shè)計(jì)的文章,請(qǐng)瀏覽JavaWorld的UI設(shè)計(jì)部分索引頁
    http://www.javaworld.com/channel_content/jw-ui-index.shtml


    原文地址:
    posted @ 2006-01-04 10:53 只牽這只狗 閱讀(209) | 評(píng)論 (0)編輯 收藏

    2.3 業(yè)務(wù)邏輯層設(shè)計(jì)

      2.3.1 動(dòng)態(tài)加載技術(shù)

      如果一次性獲取完整的先序樹,構(gòu)造成xml提供給JavaScript解析,數(shù)據(jù)量越大,消耗的資源越多,客戶端響應(yīng)延遲時(shí)間就越長(zhǎng),因此對(duì)于大數(shù)據(jù)量的樹,采用動(dòng)態(tài)加載方式,即每次單擊“+”圖片時(shí),判斷是否已加載子節(jié)點(diǎn)數(shù)據(jù),如果未加載則通過Ajax的XMLHTTP組件XMLHTTPRequest對(duì)象異步發(fā)送請(qǐng)求,連接服務(wù)器執(zhí)行SQL 語句“select * from tree_class where parent = ?order by classcode ”獲取節(jié)點(diǎn)數(shù)據(jù)。相關(guān)JavaScript 代碼如下:

    /*判斷是否已經(jīng)加載數(shù)據(jù),未加載則訪問服務(wù)器加載數(shù)據(jù)*/

    dhtmlTree.prototype.Loading=function(pObject){
     if(((pObject.XMLload==0)&&(this.XMLsource))&&(!this.XMLloading)){
      pObject.XMLload=1;
      this.loadXML(this.XMLsource+getUrlSymbol(this.XMLsource)+"id="+escape(pObject.id));
     }
    }
    dtmlXMLObject.prototype.loadXML=function(url){//加載數(shù)據(jù)
     try {
      this.xmlDoc = new XMLHttpRequest();
      /*通過GET方法異步連接到 url 加載數(shù)據(jù)*/
      this.xmlDoc.open("GET", url,true);//true:異步;false:同步
      this.xmlDoc.send(null);
     } catch(e){
      this.xmlDoc = new ActiveXObject("Microsoft.XMLHTTP");//使用IE
      this.xmlDoc.open("GET", url,true);//true:異步;false:同步
      this.xmlDoc.send(null);
     }
     return this.xmlDoc.responseXML;
    }

      每次只取同一個(gè)父節(jié)點(diǎn)ParentId的子節(jié)點(diǎn)序列,按XML格式封裝成樹的文檔結(jié)構(gòu),例如:

    <tree id="0">
    <leaf child=”1" name="國(guó)防科技大學(xué)" id="1" im0="leaf.gif" im1="folderOpen.gif" im2=" folderClosed.gif"/>
    </tree>

      提供給JavaScript的dhtmlTreeObject.prototype.insertItem()解析并組織好html輸出節(jié)點(diǎn);其中 child:1表示有子節(jié)點(diǎn),0表示沒有子節(jié)點(diǎn);im0表示沒有子節(jié)點(diǎn)時(shí)的圖標(biāo);im1表示有子節(jié)點(diǎn)并且打開節(jié)點(diǎn)時(shí)的圖標(biāo);im2表示有子節(jié)點(diǎn)并且關(guān)閉時(shí)的圖標(biāo);所以還可以在構(gòu)造XML時(shí)自定義圖標(biāo)。

      2.3.2 樹型結(jié)構(gòu)的構(gòu)造

      從數(shù)據(jù)庫中返回的是有序的先序樹,而XML是完整的樹型結(jié)構(gòu)文檔,所以將樹型數(shù)據(jù)構(gòu)造成預(yù)定義的XML格式,只需從根節(jié)點(diǎn)開始,遍歷一遍樹,即可將樹全部生成。相關(guān)JavaScript代碼如下:

    /*動(dòng)態(tài)加載樹的構(gòu)造方法*/

    dtmlXMLObject.prototype.constructTree=function(){

    //采用動(dòng)態(tài)加載時(shí)獲取的xml數(shù)據(jù),解析樹型數(shù)據(jù)

    var node=this.XMLLoader.getXMLTopNode("tree");

    var parentId=node.getAttribute("id");

    for(var i=0;i<node.childNodes.length;i++) { //逐個(gè)解析xml文件的leaf節(jié)點(diǎn)

     if((node.childNodes[i].nodeType==1)&&(node.childNodes[i].tagName == "leaf")){
      var name=node.childNodes[i].getAttribute("text");
      …………
      var temp=dhtmlObject.a0Find(parentId);//獲取父節(jié)點(diǎn)對(duì)象
      temp.XMLload=1;//已加載
      //構(gòu)造html輸出節(jié)點(diǎn)
      dhtmlObject.insertItem(parentId,cId,name,im0,im1,im2,chd);
      dhtmlObject.addDragger = this;//設(shè)置可拖放的對(duì)象
     };
    }

      2.3.3 樹型結(jié)構(gòu)的維護(hù)

      在維護(hù)樹型結(jié)構(gòu)表時(shí),刪除節(jié)點(diǎn)較為簡(jiǎn)單,SQL 語句為: "delete from tree_class where classcode like′"+ classcode +"%′",即可將其節(jié)點(diǎn)和孩子一并刪除;增加節(jié)點(diǎn)時(shí),分為前插、后插、和插入子節(jié)點(diǎn)三種情況,前兩種情況需要更新遞歸更新類別代碼,后者只需找到父節(jié)點(diǎn)的孩子的最大類別代碼加1 后,作為增加節(jié)點(diǎn)的類別代碼;通過拖放來改變樹的結(jié)構(gòu)時(shí),只需將拖動(dòng)節(jié)點(diǎn)的parentId更新為目標(biāo)節(jié)點(diǎn)的Classid即可,對(duì)應(yīng)的SQL語句為:"update tree_class set parentId = "+ classidTo+" where classid = "+ classidFrom。

      3、效率分析

      對(duì)于樹的存儲(chǔ)一般有兩種形式:二維表和鏈表,遍歷方式一般也有深度遍歷和廣度遍歷兩種方式,遍歷的時(shí)間復(fù)雜度都是O( n )。用二維表存儲(chǔ)時(shí),在內(nèi)存中用數(shù)組的下標(biāo)能準(zhǔn)確定位節(jié)點(diǎn)的父節(jié)點(diǎn)、兄弟節(jié)點(diǎn)所在的數(shù)組下標(biāo)。數(shù)據(jù)庫中節(jié)點(diǎn)的定位也是準(zhǔn)確的,但是將節(jié)點(diǎn)信息從數(shù)據(jù)庫中讀到內(nèi)存中時(shí),如果無法通過內(nèi)存數(shù)組下標(biāo)定位節(jié)點(diǎn)信息,那么就必須遍歷一遍尋找一個(gè)節(jié)點(diǎn),n 個(gè)節(jié)點(diǎn)中尋找一個(gè)節(jié)點(diǎn)的時(shí)間是O(n/2),n 個(gè)節(jié)點(diǎn)排序的時(shí)間復(fù)雜度將是O( n 2/2),這也是一般實(shí)現(xiàn)的B/S 模式的樹結(jié)構(gòu)效率低下的原因。本方案采用字典序編號(hào)方案,使得從數(shù)據(jù)庫中取得的樹是已經(jīng)排序的,直接遍歷生成客戶頁面程序,時(shí)間復(fù)雜度為O( n )。

      4、結(jié) 論

      本文討論了基于Ajax的動(dòng)態(tài)樹型結(jié)構(gòu)的實(shí)現(xiàn)方案,支持無刷新動(dòng)態(tài)維護(hù)樹的節(jié)點(diǎn)信息,支持拖放節(jié)點(diǎn)改變樹的節(jié)點(diǎn)結(jié)構(gòu)以及次序;同時(shí)采用數(shù)據(jù)庫存儲(chǔ)節(jié)點(diǎn)信息,保證了該方案有一定的通用性,此外結(jié)合XML描述樹的節(jié)點(diǎn)信息,使得任何按本方案預(yù)定的xml文檔描述的信息都可以通過樹來展現(xiàn)。本方案已經(jīng)應(yīng)用在我校的數(shù)字迎新系統(tǒng)以及老百姓大藥房信息系統(tǒng)中。

    posted @ 2005-12-30 08:32 只牽這只狗 閱讀(392) | 評(píng)論 (0)編輯 收藏

    2.1 表示層實(shí)現(xiàn)

      類似Windows資源管理器的文件夾模式,節(jié)點(diǎn)的圖片樣式如表1所示。對(duì)于每個(gè)節(jié)點(diǎn)的DHTML 代碼,需要包含節(jié)點(diǎn)的位置、前導(dǎo)圖片、樣式、針對(duì)該節(jié)點(diǎn)的其他操作等。同時(shí)為了節(jié)點(diǎn)顯示的連貫性,還需一些前導(dǎo)圖片。

      表1 樹節(jié)點(diǎn)的前的圖片樣式表

     對(duì)于樹的非葉子節(jié)點(diǎn),圖片和節(jié)點(diǎn)信息等,采用一個(gè)DIV ( division) 容器包含。DIV 等容器是DHTML 的基礎(chǔ),使用它可以通過腳本程序?qū)ζ鋵傩赃M(jìn)行操作,如設(shè)置其style 樣式的display 屬性來控制子節(jié)點(diǎn)的展開和隱藏。節(jié)點(diǎn)的位置、前導(dǎo)圖片、樣式、針對(duì)該節(jié)點(diǎn)的其他的操作等都放入容器中,例:

    < DIV id =mParentID>
    < IMG align = center border = 0 onclick =″nodeExpand (‘leafid’)″ name = m1Tree src =′Tplus.gif′>
    < IMG align = center border = 0 name = m1Folder src =′folderClosed. gif′> 計(jì)算機(jī)學(xué)院 </p>

      葉子節(jié)點(diǎn)無需容器直接輸出即可。

      當(dāng)點(diǎn)擊某節(jié)點(diǎn)前的“ + ”、“ - ”圖片時(shí)通過DIV 的style 樣式的display 屬性控制子節(jié)點(diǎn)的展開和隱藏。display:“none”(隱藏,不可見),display:“block”(顯示) 。相關(guān)JavaScript 代碼如下:

    if (expandChild.style.display = =″none″){
     // 當(dāng)前為隱藏狀態(tài),執(zhí)行展開動(dòng)作
     this.Loading(parentObject);//判斷該分支的數(shù)據(jù)是否已經(jīng)加載
     expandChild.style.display =″block″;
    if (para2 = =″last″)
     parentObject.src =″Lminus. gif″; // 最后一個(gè)節(jié)點(diǎn)
    else
     parentObject.src = ″Tminus. gif″; // 顯示┠
     expandFolder.src = ″folderOpen. gif″;
    }else {
     // 將當(dāng)前節(jié)點(diǎn)的子節(jié)點(diǎn)全部隱藏
     expandChild.style.display = ″none″;
     if (para2 = = ″last″)
      parentObject.src = ″Lplus. gif″;
     else
      parentObject.src = ″Tplus. gif″;
      expandFolder.src = ″folderClosed. gif″;
    }

      2.2 樹型表結(jié)構(gòu)設(shè)計(jì)

      我們以數(shù)據(jù)庫為載體記錄節(jié)點(diǎn)的變化,樹型表結(jié)構(gòu)至少要有以下字段:節(jié)點(diǎn)的編號(hào)(CLASSID) ,對(duì)節(jié)點(diǎn)的描述(ClassName),父節(jié)點(diǎn)的編號(hào)(ParentId),這些是構(gòu)建樹結(jié)構(gòu)所必須的信息。同時(shí)引入節(jié)點(diǎn)的類別代碼(ClassCode),節(jié)點(diǎn)的級(jí)別(ClassLevel),是否葉子節(jié)點(diǎn) (Terminated)等輔助字段,記錄節(jié)點(diǎn)次序,實(shí)體關(guān)系圖如圖3所示。


    圖 3 樹型表結(jié)構(gòu)示意圖

      樹遍歷的時(shí)間復(fù)雜度是O( n ),但是將樹信息存放到數(shù)據(jù)庫后,就不能按傳統(tǒng)的方式遍歷樹,必須使用SQL 語句訪問數(shù)據(jù)庫表的內(nèi)容,而一次性取的數(shù)據(jù)量越多,消耗的資源也越多,用戶等待的時(shí)間就越長(zhǎng)。如果將無序的數(shù)據(jù)從數(shù)據(jù)庫中讀出,在服務(wù)器端,必須將排序后的樹送到客戶端顯示。因此,最好從數(shù)據(jù)庫讀出已排好序的樹。

      我們知道,字符串排序是按照字典序形式。結(jié)合SQL 語句的特點(diǎn)和樹結(jié)構(gòu)特點(diǎn),數(shù)據(jù)庫表中,節(jié)點(diǎn)的類別代碼采用多級(jí)字符串形式,如AAABBBCCC,從樹根節(jié)點(diǎn)開始,每向下一級(jí)字符串就增加一級(jí),并且子節(jié)點(diǎn)類別代碼以父節(jié)點(diǎn)類別代碼開始,再開始本級(jí)的類別代碼。同級(jí)的節(jié)點(diǎn)按照生成的順序編號(hào),如節(jié)點(diǎn)類別代碼為AAA 的下一級(jí)孩子類別代碼為AAAAAA,AAAAAB 等,AAAAAB 的孩子節(jié)點(diǎn)為AAAAABAAA、AAAAABAAB等。每一級(jí)編號(hào)字符的寬度與實(shí)際的應(yīng)用關(guān)聯(lián),如AAA~ZZZ 一級(jí)則有263 個(gè)節(jié)點(diǎn),如果不夠用再增加一個(gè)字符用于編碼。該巧妙的編號(hào)方式。使得在執(zhí)行SQL 語句select * from tree_class order by classcode 后,一次獲得完整的先序.

    原文鏈接:http://www.7dspace.com/doc/44/0512/2005122906292220003.htm

    posted @ 2005-12-30 08:31 只牽這只狗 閱讀(397) | 評(píng)論 (0)編輯 收藏


      摘 要:簡(jiǎn)要介紹了一種通用的,動(dòng)態(tài)樹型結(jié)構(gòu)的實(shí)現(xiàn)方案,該方案基于Asynchronous JavaScript and XML,結(jié)合Struts框架設(shè)計(jì)實(shí)現(xiàn)了結(jié)構(gòu)清晰、擴(kuò)展性良好的多層架構(gòu),數(shù)據(jù)存儲(chǔ)于數(shù)據(jù)庫,結(jié)合XML描述樹的節(jié)點(diǎn)信息,使得任何按預(yù)定的XML文檔描述的信息都可以通過動(dòng)態(tài)樹來展現(xiàn)。

      關(guān)鍵詞:MVC模式;Ajax;樹型結(jié)構(gòu);字典序

      樹型結(jié)構(gòu)是一類應(yīng)用非常廣泛的數(shù)據(jù)結(jié)構(gòu)。人類社會(huì)中宗族的族譜和現(xiàn)代企業(yè)的組織形式都是樹型結(jié)構(gòu)。在計(jì)算機(jī)領(lǐng)域中,文件系統(tǒng)中文件的管理結(jié)構(gòu)、存儲(chǔ)器管理中的頁表、數(shù)據(jù)庫中的索引等也都是樹型結(jié)構(gòu)。隨著Internet的飛速發(fā)展,樹型結(jié)構(gòu)在瀏覽器/服務(wù)器(Browser/Server,簡(jiǎn)稱B/S)應(yīng)用系統(tǒng)的應(yīng)用也越來越廣泛。

      目前,在互聯(lián)網(wǎng)上廣泛存在、應(yīng)用的樹型結(jié)構(gòu)一般分為兩種:靜態(tài)和動(dòng)態(tài)結(jié)構(gòu)。靜態(tài)結(jié)構(gòu)存在最多、實(shí)現(xiàn)簡(jiǎn)單,但是靜態(tài)導(dǎo)致不能改變樹的結(jié)構(gòu)和內(nèi)容,無法反映樹的節(jié)點(diǎn)信息的變化;而實(shí)現(xiàn)相對(duì)復(fù)雜的動(dòng)態(tài)構(gòu)造樹,雖然可以動(dòng)態(tài)增加、刪除、更新節(jié)點(diǎn)信息,但是大部分不能直接拖放節(jié)點(diǎn)來改變樹的結(jié)構(gòu)以及節(jié)點(diǎn)間的次序,并且反復(fù)刷新整個(gè)頁面,給用戶維護(hù)帶來了許多不便。本文提出了一種基于Ajax (Asynchronous JavaScript and XML)通用的、動(dòng)態(tài)加載節(jié)點(diǎn)的解決方案。實(shí)現(xiàn)上采用J2EE多層架構(gòu),樹節(jié)點(diǎn)的描述信息采用數(shù)據(jù)庫存儲(chǔ),以可擴(kuò)展標(biāo)記語言(eXtensible Markup Language,簡(jiǎn)稱XML)展現(xiàn)給JavaScript解析,支持無刷新地增加、刪除、更新節(jié)點(diǎn)信息,以及拖放節(jié)點(diǎn)來改變樹的結(jié)構(gòu)和節(jié)點(diǎn)間的次序。文中第1部分簡(jiǎn)要介紹了Ajax技術(shù);第2部分詳細(xì)介紹了該方案的技術(shù)實(shí)現(xiàn)過程;第3部分分析了該方案的效率。

      1、Ajax簡(jiǎn)介

      Ajax概念的最早提出者Jesse James Garrett認(rèn)為:Ajax并不是一門新的語言或技術(shù),它實(shí)際上是幾項(xiàng)技術(shù)按一定的方式組合在共同的協(xié)作中發(fā)揮各自的作用,它包括:

      ·使用擴(kuò)展超媒體標(biāo)記語言(eXtended Hypertext Markup Language,簡(jiǎn)稱XHTML)和級(jí)聯(lián)樣式單(Cascading Style Sheet,簡(jiǎn)稱CSS)標(biāo)準(zhǔn)化呈現(xiàn);

      ·使用文檔對(duì)象模型(Document Object Model,簡(jiǎn)稱DOM)實(shí)現(xiàn)動(dòng)態(tài)顯示和交互;

      ·使用可擴(kuò)展標(biāo)記語言(eXtensible Markup Language,簡(jiǎn)稱XML)和可擴(kuò)展樣式表轉(zhuǎn)換(eXtensible Stylesheet Language Transformation,簡(jiǎn)稱XSLT)進(jìn)行數(shù)據(jù)交換與處理;

      ·使用XMLHTTP組件XMLHttpRequest對(duì)象進(jìn)行異步數(shù)據(jù)讀取;

      ·最后用JavaScript綁定和處理所有數(shù)據(jù)。

      Ajax的工作原理如圖1所示,它相當(dāng)于在用戶和服務(wù)器之間加了一個(gè)中間層,使用戶操作與服務(wù)器響應(yīng)異步化。并不是所有的用戶請(qǐng)求都提交給服務(wù)器,像— 些數(shù)據(jù)驗(yàn)證和數(shù)據(jù)處理等都交給Ajax引擎處理,只有確定需要從服務(wù)器讀取新數(shù)據(jù)時(shí)再由Ajax引擎代為向服務(wù)器提交請(qǐng)求。這樣就把一些服務(wù)器負(fù)擔(dān)的工作轉(zhuǎn)嫁到客戶端,利用客戶端閑置的處理能力來處理,減輕服務(wù)器和帶寬的負(fù)擔(dān),從而達(dá)到節(jié)約ISP的空間及帶寬租用成本的目的。


    圖 1 未使用Ajax(a)和使用Ajax(b)的web應(yīng)用比較

      2、總體設(shè)計(jì)方案

      傳統(tǒng)的服務(wù)器程序采用Model 1開發(fā)模型,通常將業(yè)務(wù)邏輯、服務(wù)器端處理過程和HTML代碼集中在一起表示,快速完成應(yīng)用開發(fā)。Model 1 在小規(guī)模應(yīng)用開發(fā)時(shí)優(yōu)勢(shì)明顯,但是應(yīng)用實(shí)現(xiàn)一般是基于過程的,一組服務(wù)器頁面實(shí)現(xiàn)一個(gè)流程,如果流程改動(dòng)將導(dǎo)致多個(gè)地方修改,非常不利于應(yīng)用的擴(kuò)展和更新。此外業(yè)務(wù)邏輯和表示邏輯混合在服務(wù)器頁面中,耦合緊密,無法模塊化,導(dǎo)致代碼無法復(fù)用。

      Model 2則解決了這些問題,它是面向?qū)ο蟮腗VC模式(Model-View-Controller,模型-視圖-控制器)在Web開發(fā)中的應(yīng)用,Model表示應(yīng)用的業(yè)務(wù)邏輯,View是應(yīng)用的表示層頁面,Controller是提供應(yīng)用的處理過程控制。通過這種MVC設(shè)計(jì)模式把應(yīng)用邏輯,處理過程和顯示邏輯劃分成不同的組件、模塊實(shí)現(xiàn),組件間可以進(jìn)行交互和重用。

      本方案是采用J2EE的多層架構(gòu),設(shè)計(jì)時(shí)結(jié)合Struts框架將表示層、業(yè)務(wù)邏輯層和數(shù)據(jù)層劃分成不同的模塊。表示層專注于樹的外觀顯示,業(yè)務(wù)邏輯層為服務(wù)器端處理程序,處理樹的生成、變化,為減少耦合性,該程序全部模塊化實(shí)現(xiàn),不在表示頁面嵌入服務(wù)器程序;模型層是數(shù)據(jù)的存儲(chǔ)和表示。下面分別介紹各層實(shí)現(xiàn)。

    原文鏈接:http://www.7dspace.com/doc/44/0512/2005122906292220003.htm
    posted @ 2005-12-30 08:28 只牽這只狗 閱讀(305) | 評(píng)論 (0)編輯 收藏

    主站蜘蛛池模板: 亚洲精品无码中文久久字幕| 亚洲综合国产精品| 亚洲精品国产精品乱码不卡| 精品国产日韩亚洲一区| 亚洲av永久无码制服河南实里| 亚洲高清在线mv| 亚洲熟妇无码一区二区三区| 国产亚洲精品欧洲在线观看| 国产一级高青免费| 91久久精品国产免费直播| 成人毛片免费视频| 国产偷窥女洗浴在线观看亚洲| 亚洲尹人香蕉网在线视颅| 亚洲国产精品免费观看| 产传媒61国产免费| 99久久免费中文字幕精品| 暖暖在线日本免费中文| 中文字幕精品亚洲无线码一区应用| 久久精品蜜芽亚洲国产AV| 亚洲国产欧美国产综合一区 | 日韩免费视频播放| 青青草原亚洲视频| 亚洲最大黄色网址| 特级毛片aaaa级毛片免费| 人妻丰满熟妇无码区免费| 日本不卡高清中文字幕免费| 亚洲日韩精品一区二区三区| 国产.亚洲.欧洲在线| v片免费在线观看| jjizz全部免费看片| 亚洲国产综合无码一区二区二三区| 亚洲国产精品婷婷久久| 亚洲欧洲无码一区二区三区| 青青操免费在线视频| 免费涩涩在线视频网| 久久精品国产亚洲一区二区| 亚洲精品无码av中文字幕| 一级毛片免费不卡在线| 国产午夜免费福利红片| 亚洲黄色免费网址| 一个人免费播放在线视频看片|