<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                ### 起點 實例非常簡單。這是一個影片出租店用的程序,計算每一位顧客的消費金額并打印報表(statement)。操作者告訴程序:顧客租了哪些影片、租期多長,程序便根據租賃時間和影片類型算出費用。影片分為三類:普通片、兒童片和新片。除了計算費用,還要為常客計算點數;點數會隨著「租片種類是否為新片」而有不同。 我以數個classes 表現這個例子中的元素。圖1.1是一張UML class diagram(類圖),用以顯示這些classes 。我會逐一列出這些classes 的代碼。 ![](https://box.kancloud.cn/2016-08-15_57b1b4f13b070.gif) 圖1.1 本例一開始的各個classes 。此圖只顯示最重要的特性。圖中所用符號是UML(Unified Modeling Language ,統一建模語言,[Fowler, UML])。 **Movie(影片)** Movie只是一個簡單的data class(純數據類)。 ~~~ public class Movie { public static final int CHILDRENS = 2; public static final int REGULAR = 0; public static final int NEW_RELEASE = 1; private String _title; //名稱 private int _priceCode; //價格(代號) public Movie(String title, int priceCode) { _title = title; _priceCode = priceCode; } public int getPriceCode() { return _priceCode; } public void setPriceCode(int arg) { _priceCode = arg; } public String getTitle (){ return _title; }; } ~~~ **Rental(租賃)** Rental class 表示「某個顧客租了一部影片」。 ~~~ class Rental { private Movie _movie; //影片 private int _daysRented; //租期 public Rental(Movie movie, int daysRented) { _movie = movie; _daysRented = daysRented; } public int getDaysRented() { return _daysRented; } public Movie getMovie() { return _movie; } } ~~~ 譯注:中文版(本書)支持網站提供本章重構過程中的各階段完整代碼(共分七個階段),并含測試。網址見于封底。 **Customer(顧客)** Customer class 用來表示顧客。就像其他classes一樣,它也擁有數據和相應的訪問函數(accessor): ~~~ class Customer { private String _name; //姓名 private Vector _rentals = new Vector(); //租借記。 public Customer (String name){ _name = name; }; public void addRental(Rental arg) { _rentals.addElement(arg); } public String getName (){ return _name; }; //譯注:續下頁... ~~~ Customer「還提供了一個用以制造報表的函數(method),圖1.2顯示這個函數帶來的交互過程(interactions )。完整代碼顯示于下一頁。 ![](https://box.kancloud.cn/2016-08-15_57b1b4f170f4e.gif) 圖1.2 statement() 的交互過程(interactions 。 ~~~ public String statement() { double totalAmount = 0; //總消費金。 int frequentRenterPoints = 0; //常客積點 Enumeration rentals = _rentals.elements(); String result = "Rental Record for " + getName() + "\n"; while (rentals.hasMoreElements()) { double thisAmount = 0; Rental each = (Rental) rentals.nextElement(); //取得一筆租借記。 //determine amounts for each line switch (each.getMovie().getPriceCode()) { //取得影片出租價格 case Movie.REGULAR: //普通片 thisAmount += 2; if (each.getDaysRented() > 2) thisAmount += (each.getDaysRented() - 2) * 1.5; break; case Movie.NEW_RELEASE: //新片 thisAmount += each.getDaysRented() * 3; break; case Movie.CHILDRENS: //兒童。 thisAmount += 1.5; if (each.getDaysRented() > 3) thisAmount += (each.getDaysRented() - 3) * 1.5; break; } // add frequent renter points (累計常客積點。 frequentRenterPoints ++; // add bonus for a two day new release rental if ((each.getMovie().getPriceCode() == Movie.NEW_RELEASE) && each.getDaysRented() > 1) frequentRenterPoints ++; //show figures for this rental(顯示此筆租借記錄) result += "\t" + each.getMovie().getTitle()+ "\t" + String.valueOf(thisAmount) + "\n"; totalAmount += thisAmount; } //add footer lines(結尾打印) result += "Amount owed is " + String.valueOf(totalAmount) + "\n"; result += "You earned " + String.valueOf(frequentRenterPoints) + " frequent renter points"; return result; } ~~~ **對此起始程序的評。** 這個起始程序給你留下什么印象?我會說它設計得不好,而且很明顯不符合面向對象精神。對于這樣一個小程序,這些缺點其實沒有什么關系。快速而隨性(quick and dirty )地設計一個簡單的程序并沒有錯。但如果這是復雜系統中具有代表性的一段, 那么我就真的要對這個程序信心動搖了。Customer 里頭那個長長的statement() 做的事情實在太多了,它做了很多原本應該由其他完成的事情。 即便如此,這個程序還是能正常工作。所以這只是美學意義上的判斷,只是對丑陋代碼的厭惡,是嗎?在我們修改這個系統之前的確如此。編譯器才不會在乎代碼好不好看呢。但是當我們打算修改系統的時候,就涉及到了人,而人在乎這些。差勁的系統是很難修改的,因為很難找到修改點。如果很難找到修改點,程序員就很有可能犯錯,從而引入「臭蟲」(bugs)。 在這個例子里,我們的用戶希望對系統做一點修改。首先他們希望以HTML 格式打印報表,這樣就可以直接在網頁上顯示,這非常符合潮流。現在請你想一想,這個變化會帶來什么影響。看看代碼你就會發現,根本不可能在打印報表的函數中復用(reuse)目前statement() 的任何行為。你惟一可以做的就是編寫一個全新的htmlStatement() ,大量重復statement() 的行為。當然,現在做這個還不太費力,你可以把statement() 復制一份然后按需要修改就是。 但如果計費標準發生變化,又會發生什么事?你必須同時修改statement() 和htmlstatement() ,并確保兩處修改的一致性。當你后續還要再修改時,剪貼(copy-paste)問題就浮現出來了。如果你編寫的是一個永不需要修改的程序,那么剪剪貼貼就還好,但如果程序要保存很長時間,而且可能需要修改,剪貼行為就會造成潛在的威脅。 現在,第二個變化來了:用戶希望改變影片分類規則,但是還沒有決定怎么改。他 們設想了幾種方案,這些方案都會影響顧客消費和常客積點的計算方式。作為一個經驗豐富的開發者,你可以肯定:不論用戶提出什么方案,你惟一能夠獲得的保證就是他們一定會在六個月之內再次修改它。 為了應付分類規則和計費規則的變化,程序必須對statement() 作出修改。但如果我們把statement() 內的代碼拷貝到用以打印報表的函數中,我們就必須確保將來的任何修改在兩個地方保持一致。隨著各種規則變得愈來愈復雜,適當的修改點愈來愈難找,不犯錯的機會也愈來愈少。 你的態度也許傾向于「盡量少修改程序」:不管怎么說,它還運行得很好。你心里頭牢牢記著那句古老的工程學格言:「如果它沒壞,就別動它」。這個程序也許還沒壞掉,但它帶來了傷害。它讓你的生活比較難過,因為你發現很難完成客戶所需的修改。這時候就該重構技術粉墨登場了。 TIP:如果你發現自己需要為程序添加一個特性,而代碼結構使你無法很方便地那么做,那就先重構那個程序,使特性的添加比較容易進行,然后再添加特性。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看