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

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

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

    ivaneeo's blog

    自由的力量,自由的生活。

      BlogJava :: 首頁 :: 聯系 :: 聚合  :: 管理
      669 Posts :: 0 Stories :: 64 Comments :: 0 Trackbacks

    #

    范例(Examples):有局部變量(Using Local Variables)

    是的,就在局部變量,包括傳進源函數的參數和源函數所聲明的臨時變量。局部變量的作用域僅限于源函數,所以當我使用Extract Method(110)時,必須花費額外工夫去處理這些變量.某些時候它們甚至可能妨礙我,使我根本無法進行這項重構.

    局部變量最簡單的情況是:被提煉碼只是讀取這些變量的值,并不修改它們.這種情況下我可以簡單地將它們當作參數傳給目標函數.所以如果我面對下列函數:
    void printOwing() {
        Enumeration e = _orders.elements();
        double outstanding = 0.0;

        printBanner();

        // calculate outstanding
        while(e.hasMoreElements()) {
           Order each = (Order) e.nextElement();
           outstanding += each.getAmount();
        }

        //print details
       
    System.out.println("name:" + _name);
       
    System.out.println("amount" + outstanding);
    }

    我就可以將[打印詳細信息]這一部分提煉為[帶一個參數的函數]:

    void printOwing() {
        Enumeration e = _orders.elements();
        double outstanding = 0.0;

        printBanner();


        // calculate outstanding
        while(e.hasMoreElements()) {
           Order each = (Order) e.nextElement();
           outstanding += each.getAmount();
        }
       printDetails(outstanding);
    }

    void printDetails(double outstanding) {
        System.out.println("name:" + _name);
       
    System.out.println("amount" + outstanding);
    }

    必要的話,你可以用這種手法處理多個局部變量.

    posted @ 2005-08-24 15:13 ivaneeo 閱讀(219) | 評論 (0)編輯 收藏

    范例(Examples):無局部變量(No Local Variables)
    在最簡單的情況下,Extract Method(110)易如反掌。請看下列函數:

    void printOwing() {
        Enumeration e = _orders.elements();
        double outstanding = 0.0;

        //print banner
        System.out.println("********************************");
        System.out.println("********* Customer Owes **********");
        System.out.println("********************************");

        // calculate outstanding
        while(e.hasMoreElements()) {
           Order each = (Order) e.nextElement();
           outstanding += each.getAmount();
        }

        //print details
       
    System.out.println("name:" + _name);
       
    System.out.println("amount" + outstanding);
    }

    我們可以輕松提煉出[打印banner]的代碼。我只需要剪切、粘貼、再插入一個函數調用動作就行了:

    void printOwing() {
        Enumeration e = _orders.elements();
        double outstanding = 0.0;

        printBanner();

        // calculate outstanding
        while(e.hasMoreElements()) {
           Order each = (Order) e.nextElement();
           outstanding += each.getAmount();
        }

        //print details
       
    System.out.println("name:" + _name);
       
    System.out.println("amount" + outstanding);
    }

    void printBanner() {
       
    //print banner
        System.out.println("********************************");
        System.out.println("********* Customer Owes **********");
        System.out.println("********************************");
    }
    posted @ 2005-08-24 14:59 ivaneeo 閱讀(195) | 評論 (0)編輯 收藏

    作法(Mechanics)
      • 創造一個新函數,根據這個函數的意圖來給它命名(以它[做什么]來命名,而不是以它[怎么做]命名)。 --》即使你想要提煉(extract)的代碼非常簡單,例如只是一條消息或一個函數調用,只要新函數的名稱能夠以更好方式昭示代碼意圖,你也應該提煉 它。但如果你想不出一個更有意義的名稱,就別動。
      • 將提煉出的代碼從源函數(source)拷貝到新建的目標函數(target)中。
      • 仔細檢查提煉出的代碼,看看其中是否引用了[作用域(scope)限于源函數]的變量(包括局部變量和源函數參數)。
      • 檢查是否有[僅用于被提煉碼]的臨時變量(temporary variables)。如果有,在目標函數中將它們聲明為臨時變量。
      • 檢查被提煉碼,看看是否有任何局部變量(local-scope variables)的值被它改變。如果一個臨時變量值被修改了,看看是否可以被提煉碼處理為一個查詢(query),并將結果賦值給相關變量。如果很難 這樣做,或如果被修改的變量不止一個,你就不能僅僅將這段代碼原封不動地提煉出來。你可能需要先使用Split Temporary Variable(128),然后再嘗試提煉。也可以使用Replace Temp with Query(120)將臨時變量消滅掉。
      • 將被提煉碼中需要讀取的局部變量,當作參數傳給目標函數。
      • 處理完所有局部變量之后,進行編譯。
      • 在源函數中,將被提煉碼替換為[對目標函數的調用]。--》如果你將任何臨時變量移到目標函數中,請檢查它們原本的聲明式是否在被提煉碼的外圍。如果是,現在你可以刪除這些聲明式了。
      • 編譯,測試。
    posted @ 2005-08-24 11:04 ivaneeo 閱讀(197) | 評論 (0)編輯 收藏

    動機(Motivation)
    Extract Method是最常用的重構手法之一。當我看見一個過長的函數或者一段需要注釋才能讓人理解用途的代碼,我就會將這段代碼放進一個獨立函數中。

    有數個原因造成我喜歡簡短而有良好命名的函數。首先,如果每個函數的粒度都很?。╢inely grained),那么函數之間彼此復用的機會就更大;其次,這會使高層函數碼讀起來就像一系列注釋;再者,如果函數都是細粒度,那么函數的覆寫 (override)也會更容易些。

    一個函數多長才算合適?在我看來,長度不是問題,關鍵在于函數名稱和函數本體之間的語義距離(semantic distance)。如果提煉動作(extracting)可以強化代碼的清晰度,那就去做,就算函數名稱比提煉出來的代碼還長也無所謂。
    posted @ 2005-08-24 10:54 ivaneeo 閱讀(239) | 評論 (0)編輯 收藏

    Extract Method

    將這段代碼放進一個獨立函數中,并讓函數名稱解釋該函數的用途。

    void printOwing(double amount) {
        printBanner();

        //print details
        System.out.println("name:" + _name);
        System.out.println("amount" + amount);
    }

                             |  |
                             |  |
                            \  /

    void printOwing(double amount) {

        printBanner();

        printDetails(amount);
    }

    void printDetails(double amount) {
        System.out.println("name:" + _name);

        System.out.println("amount" + amount);
    }
    posted @ 2005-08-24 10:33 ivaneeo 閱讀(195) | 評論 (0)編輯 收藏

     隨著人們對動態語言興趣的日益濃厚,越來越多的人都遇到了閉包(Closures )和或塊(Blocks)等概念。有著C/C++/Java/C#等語言背景的人因為這些語言本身沒有閉包這個概念,所以可能不太了解閉包。本文將簡單的介紹一下閉包的概念,那些有大量支持閉包語言編程經驗的人也許覺得本文不會太有意思。

        閉包的概念已經提出很長時間了。我第一次碰到這它是在smalltalk中,那時候還叫做塊(blocks)。Lisp語言中用的很多。Ruby中也有同樣的功能-這也是Ruby用戶喜歡Ruby的一個原因。

        本質上來說,一個閉包是一塊代碼,它們能作為參數傳遞給一個方法調用。我將通過一個簡單的例子來闡述這個觀點。假設我們有一個包含一些雇員對象的列表,然后我想列出職位為經理的員工,這樣的員工可以通過IsManager判斷。在C#里,我們可能會寫出下面類似的代碼:

      public static IList Managers(IList emps) {
        IList result = new ArrayList();
        foreach(Employee e in emps)
          if (e.IsManager) result.Add(e);
        return result;
      }
    

        在一種支持閉包的語言中,比如Ruby,我們可以這樣寫:

      def managers(emps)
    	return emps.select {|e| e.isManager}
      end
      

        select是Ruby中定義的集合結構中的一個方法,它接受一個block,也就是閉包,作為一個參數。在Ruby中,閉包寫在一對大括號中(不止這一種方法,另一種為do .. end)。如果這個塊也接受參數,你可以將這些參數放到兩個豎線之間。select方法循環迭代給定的數組,對每個元素執行給定的block,然后將每次執行block返回true的元素組成一個新的數組再返回。

        現在,如果你是C程序員你也許要想,通過函數指針也可以實現,如果你是JAVA程序員,你可能回想我可以用匿名內類來實現,而一個C#者則會想到代理(delegate)。這些機制和閉包類似,但是它們和閉包之間有兩個明顯得區別。

        第一個是形式上的不同(The first one is a formal difference)。閉包可以引用它定義時候可見的變量。看看下面的方法:

    def highPaid(emps)
    	threshold = 150
    	return emps.select {|e| e.salary > threshold}
    end
      

        注意select的block代碼中引用了在包含它的方法中的局部變量,而其它不支持真正閉包的語言使用其它方法達到類似功能的方法則不能這樣做。閉包還允許你做更有趣的事情,比如下面方法:

    def paidMore(amount)
    	return Proc.new {|e| e.salary > amount}
    end
    

        這個方法返回一個閉包,實際上它返回一個依賴于傳給它的參數的閉包。我可以用一個參數創建一個這樣的方法,然后再把它賦給另一個變量。

    highPaid = paidMore(150)
    

        變量 highPaid 包含了一段代碼(在Ruby中是一個Proc對象),這段代碼將判斷一個對象的salary屬性是否大于150。我們可以這樣使用這個方法:

    john = Employee.new
    john.salary = 200
    print highPaid.call(john)
      

          表達式highPaid.call(john)調用我之前定義的代碼,這時候此代碼中的amount已經在創建這方法的時候綁定為150。即使現在我執行print 的時候,150已經不在它的范圍內了,但是amount和150之間的綁定依然存在。

        所以,閉包的第一個關鍵點是閉包是一段代碼加上和定義它的環境之間的綁定(they are a block of code plus the bindings to the environment they came from)。這是閉包和函數指針等其它相似技術的不同點(java匿名內類可以訪問局部變量,但是只有當這些內類是final的時候才行)。

        第二個不同點不是定義形式的不同,但是也同樣重要。(The second difference is less of a defined formal difference, but is just as important, if not more so in practice)。支持閉包的語言允許你用很少的語法去定義一個閉包,盡管這點可能不是很重要的一點,但我相信這點是至關重要的-這是使得人們能很自然的使用閉包的關鍵點??纯碙isp,Smalltalk和Ruby,閉包遍布各處-比其它語言中類似的使用多很多。綁定局部變量是它的特點之一,但我想最大的原因是使用閉包的語法和符號非常簡單和清楚。

        一個很好的相關例子是從Smalltalk程序員到JAVA程序員,開始時很多人,包括我,試驗性的將在Smalltalk中使用閉包的地方在Java中使用匿名內類來實現。但結果使得代碼變得混亂難看,所以我們不得不放棄。

       我在Ruby經常使用閉包,但我不打算創建Proc對象,然后傳來傳去。大多數時間我用閉包來處理前面我提到的select等基于集合對象的方法。閉包另一個重要用途是'execute around method',比如處理一個文件:

    File.open(filename) {|f| doSomethingWithFile(f)}
    

       這里open方法打開一個文件,然后執行給定的block,然后關閉它。這樣處理非常方便,尤其是對事務(要求commit或者rollback),或者其它的你需要在處理結束時候作一些收尾處理的事情。我在我的xml文檔轉換中廣泛使用這個優點。

       閉包的這些用法顯然遠不如用Lisp語言的人遇到的多,即使我,在使用沒有閉包支持的語言的時候,也會想念這些東西。閉包就像一些你第一眼見到覺得不怎么樣的東西,但你很快就會喜歡上它們。

    posted @ 2005-08-23 17:06 ivaneeo 閱讀(248) | 評論 (0)編輯 收藏

    如果你需要注釋來解釋一塊代碼做了什么,試試Extract Method(110);如果method已經提煉出來,但還是需要注釋來解釋其行為,試試Rename Method(273);如果你需要注釋說明某些系統的需求規格,試試Introduce Assertion(267)。

    如果你不知道該做什么,這才是注釋的良好運用時機。除了用來記述將來的打算之外,注釋還可以用來標記你并無十足把握的區域。你可以在注釋里寫下自己[為什么做某某事]。這類信息可以幫助將來的修改著,尤其是那些健忘的家伙。
    posted @ 2005-08-19 17:35 ivaneeo 閱讀(289) | 評論 (0)編輯 收藏

    subclass應該繼承superclass的函數和數據。但如果它們不想或不需要繼承,又該怎么辦呢?它們得到所有禮物,卻只從中挑選幾樣來玩!

    按傳統說法,這就意味繼承系統設計錯誤。你需要為這個subclass新建一個兄弟(sibling class),再運用Push Down Method(328)和Push Down Field(329)把所有用不到的函數下推給那兄弟。這樣一來superclass就持有所有subclasses共享的東西。常常你會聽到這樣的建議:所有superclasses都應該是抽象的(abstract)。

    既然使用[傳統說法]這個略帶貶義的詞,你就可以猜到,我們不建議你這么做,起碼不建議你每次都這么做。我們經常利用subclassing手法來復用一些行為,并發現這可以很好地應用于日常工作。這也是一種壞味道,我們不否認,但氣味通常并不強烈。所以我們說:如果Refused Bequest引起困惑和問題,請遵循傳統忠告。但不必認為你每次都得那么做。十有八九這種壞味道很淡,不值得理睬。

    如果subclass復用了superclass的行為(實現),卻又不原意支持superclass得接口,Refused Bequest的壞味道就會變得濃烈。拒絕繼承superclass的實現,這一點我們不介意;但如果拒絕繼承superclass的接口,我們不以為然。不過即使你不原意繼承接口,也不要胡亂修改繼承體系,你應該運用Replace Inheritance with Delegation(352)來達到目的。
    posted @ 2005-08-19 17:26 ivaneeo 閱讀(382) | 評論 (0)編輯 收藏

    所謂Data Class是指:它們擁有一些值域(fields),以及用于訪問(讀寫)這些值域的函數,除此之外一無長物。這樣的classes只是一種[不會說話的 數據容器],它們幾乎一定被其他classes過分細瑣地操控著。這些classes早期可能擁有public值域,果真如此你應該在別人注意到它們之 前,立刻運用Encapsulate Field(206)將它們封裝起來。如果這些classes內含容器類的值域(collection fields),你應該檢查它們是不是得到了恰當的封裝;如果沒有,就運用Encapsulate Collection(208)把它們封裝起來。對于那些不該被其他classes修改的值域,請運用Remove Setting Method(300)。

    然后,找出這些[取值/設值]函數(getting and setting methods)被其他classes運用的地點。嘗試以Move Method(142)把那些調用行為搬移到Data Class來。如果無法搬移整個函數,就運用Extract Method(110)產生一個可被搬移的函數。不久之后你就可以運用Hide Method(303)把這些[取值/設值]函數隱藏起來了。
    posted @ 2005-08-19 17:05 ivaneeo 閱讀(527) | 評論 (0)編輯 收藏

    幸好我們有兩個專門應付這種情況的工具。如果你只想修改library classes內的一兩個函數,可以運用Introduce Foreign Method(162);如果想要添加一大堆額外行為,就得運用Introduce Local Extension(164)。
    posted @ 2005-08-19 16:50 ivaneeo 閱讀(266) | 評論 (0)編輯 收藏

    僅列出標題
    共67頁: First 上一頁 49 50 51 52 53 54 55 56 57 下一頁 Last 
    主站蜘蛛池模板: 亚洲人成欧美中文字幕| 亚洲成a人片在线观看播放| 国产精品无码亚洲精品2021| 久久精品免费一区二区喷潮| 亚洲国产日韩在线| 色窝窝免费一区二区三区| 亚洲一区二区三区免费观看| 成人性生交大片免费看无遮挡| 亚洲三级中文字幕| 午夜时刻免费入口| 亚洲AV无码成人网站在线观看| 国产不卡免费视频| 国产精品一区二区三区免费| 国产亚洲精品国产| 在线看片韩国免费人成视频| 中文字幕亚洲精品无码| 日本xxwwxxww在线视频免费| 免费中文字幕视频| 亚洲A∨无码一区二区三区| 亚洲黄色免费电影| 亚洲AⅤ男人的天堂在线观看| 四虎国产精品免费久久影院| 免费精品久久天干天干| 久久久亚洲欧洲日产国码是AV| 丁香花在线观看免费观看| 国产午夜亚洲精品不卡| 亚洲日韩精品无码专区网址| 三年片在线观看免费观看大全一 | 97国免费在线视频| 久久夜色精品国产噜噜亚洲AV| 免费下载成人电影| 青娱乐在线视频免费观看| 久久亚洲精品成人综合| 好吊妞视频免费视频| 国产免费久久精品99久久| 亚洲精品国产福利在线观看| 又粗又硬又大又爽免费视频播放| 三根一起会坏掉的好痛免费三级全黄的视频在线观看 | 亚洲精品动漫在线| 免费国产真实迷j在线观看| 永久免费A∨片在线观看|