<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之旅 廣告
                ### Form Template Method(塑造模板函數) 你有一些subclasses ,其中相應的某些函數以相同順序執行類似的措施,但各措施實際上有所不同。 將各個措施分別放進獨立函數中,并保持它們都有相同的簽名式(signature),于是原函數也就變得相同了。然后將原函數上移至superclass 。 ![](https://box.kancloud.cn/2016-08-15_57b1b5e773d1b.gif) **動機(Motivation)** 繼承是「避免重復行為」的一個強大工具。無論何時,只要你看見兩個subclasses 之中有類似的函數,就可以把它們提升到superclass 。但是如果這些函數并不完全相同呢?此時的你應該怎么辦?我們仍有必要盡量避免重復,但又必須保持這些函 數之間的實質差異。 常見的一種情況是:兩個函數以相同序列(sequence)執行大致相近的措施,但是各措施不完全相同。這種情況下我們可以將「執行各措施」的序列移至superclass , 并倚賴多態(polymorphism )保證各措施仍得以保持差異性。這樣的函數被稱為Template Method (模板函數)[Gang of Four]。 **作法(Mechanics)** - 在各個subclass 中分解目標函數,使分解后的各個函數要不完全相同,要不完全不同。 - 運用Pull Up Method 將各subclass 內寒全相同的函數上移至superclass 。 - 對于那些(剩余的、存在于各subclasses 內的)完全不同的函數,實施Rename Method,使所有這些函數的簽名式(signature)完全相同。 - 這將使得原函數變為完全相同,因為它們都執行同樣一組函數調用; 但各subclass 會以不同方式響應這些調用。 - 修改上述所有簽名式后,編譯并測試。 - 運用Pull Up Method 將所有原函數上移至superclass 。在superclass 中將那些「有所不同、代表各種不同措施」的函數定義為抽象函數。 - 編譯,測試。 - 移除其他subclass 中的原函數,每刪除一個,編譯并測試。 **范例:(Example)** 現在我將完成第一章遺留的那個范例。在此范例中,我有一個Customer ,其中有兩個用于打印的函數。statement() 函數以ASCII 碼打印報表(statement): ~~~ public String statement() { Enumeration rentals = _rentals.elements(); String result = "Rental Record for " + getName() + "\n"; while (rentals.hasMoreElements()) { Rental each = (Rental) rentals.nextElement(); //show figures for this rental result += "\t" + each.getMovie().getTitle()+ "\t" + String.valueOf(each.getCharge()) + "\n"; } //add footer lines result += "Amount owed is " + String.valueOf(getTotalCharge()) + "\n"; result += "You earned " + String.valueOf(getTotalFrequentRenterPoints()) + " frequent renter points"; return result; } ~~~ 函數htmlStatement() 則以HTML 格式輸出報表: ~~~ public String htmlStatement() { Enumeration rentals = _rentals.elements(); String result = "<H1>Rentals for <EM>" + getName() + "</EM></H1><P>\n"; while (rentals.hasMoreElements()) { Rental each = (Rental) rentals.nextElement(); //show figures for each rental result += each.getMovie().getTitle()+ ": " + String.valueOf(each.getCharge()) + "<BR>\n"; } //add footer lines result += "<P>You owe <EM>" + String.valueOf(getTotalCharge()) + "</EM><P>\n"; result += "On this rental you earned <EM>" + String.valueOf(getTotalFrequentRenterPoints()) + "</EM> frequent renter points<P>"; return result; } ~~~ 使用 Form Template Method 之前,我需要對上述兩個函數做一些整理,使它們成為「某個共同superclass 」下的subclass 函數。為了這一目的,我使用函數對象(method object)[Beck] 針對「報表打印工作」創建一個「獨立的策略繼承體系」(separate strategy hierarchy ),如圖11.1。 ![](https://box.kancloud.cn/2016-08-15_57b1b5e78b215.gif) 圖11.1 針對「報表輸出」使用Stategy 模式 ~~~ class Statement {} class TextStatement extends Statement {} class HtmlStatement extends Statement {} ~~~ 現在,通過Move Method,我將兩個負責輸出報表的函數分別搬移到對應的subclass 中: ~~~ class Customer... public String statement() { return new TextStatement().value(this); } public String htmlStatement() { return new HtmlStatement().value(this); } class TextStatement { public String value(Customer aCustomer) { Enumeration rentals = aCustomer.getRentals(); String result = "Rental Record for " + aCustomer.getName() + "\n"; while (rentals.hasMoreElements()) { Rental each = (Rental) rentals.nextElement(); //show figures for this rental result += "\t" + each.getMovie().getTitle()+ "\t" + String.valueOf(each.getCharge()) + "\n"; } //add footer lines result += "Amount owed is " + String.valueOf(aCustomer.getTotalCharge()) + "\n"; result += "You earned " + String.valueOf(aCustomer.getTotalFrequentRenterPoints()) + " frequent renter points"; return result; } class HtmlStatement { public String value(Customer aCustomer) { Enumeration rentals = aCustomer.getRentals(); String result = "<H1>Rentals for <EM>" + aCustomer.getName() + "</EM></H1><P>\n"; while (rentals.hasMoreElements()) { Rental each = (Rental) rentals.nextElement(); //show figures for each rental result += each.getMovie().getTitle()+ ": " + String.valueOf(each.getCharge()) + "<BR>\n"; } //add footer lines result += "<P>You owe <EM>" + String.valueOf(aCustomer.getTotalCharge()) + "</EM><P>\n"; result += "On this rental you earned <EM>" String.valueOf(aCustomer.getTotalFrequentRenterPoints()) + "</EM> frequent renter points<P>"; return result; } ~~~ 搬移之后,我還對這兩個函數的名稱做了一些修改,使它們更好地適應Strategy 模式的要求。我之所以為它們取相同名稱,因為兩者之間的差異不在于函數,而在于函數所屬的class 。如果你想試著編譯這段代碼,還必須在Customer class 中添加一個getRentals() 函數,并放寬getTotalCharge() 函數和getTotalFrequentRenterPoints() 函數的可視性(visibility )。 面對兩個subclass 中的相似函數,我可以開始實施Form Template Method 了。本重構的關鍵在于:運用 Extract Method 將兩個函數的不同部分提煉出 來,從而將相像的代碼(similar code)和變動的代碼( varying code )分開。每次提煉后,我就建立一個簽名式(signature)相同但本體(bodies)不同的函數。 第一個例子就是打印報表表頭(headers)。上述兩個函數都通過Customer 對象獲取信息,但對運算結果(字符串)的格式化方式不同。我可以將「對字符串的格式化動作」提煉到獨立函數中,并將提煉所得命以相同的簽名式(signature): ~~~ class TextStatement... String headerString(Customer aCustomer) { return "Rental Record for " + aCustomer.getName() + "\n"; } public String value(Customer aCustomer) { Enumeration rentals = aCustomer.getRentals(); String result =headerString(aCustomer); while (rentals.hasMoreElements()) { Rental each = (Rental) rentals.nextElement(); //show figures for this rental result += "\t" + each.getMovie().getTitle()+ "\t" + String.valueOf(each.getCharge()) + "\n"; } //add footer lines result += "Amount owed is " + String.valueOf(aCustomer.getTotalCharge()) + "\n"; result += "You earned " + String.valueOf(aCustomer.getTotalFrequentRenterPoints()) + " frequent renter points"; return result; } class HtmlStatement... String headerString(Customer aCustomer) { return "<H1>Rentals for <EM>" + aCustomer.getName() + "</EM></H1><P>\n"; } public String value(Customer aCustomer) { Enumeration rentals = aCustomer.getRentals(); String result = headerString(aCustomer); while (rentals.hasMoreElements()) { Rental each = (Rental) rentals.nextElement(); //show figures for each rental result += each.getMovie().getTitle()+ ": " + String.valueOf(each.getCharge()) + "<BR>\n"; } //add footer lines result += "<P>You owe <EM>" + String.valueOf(aCustomer.getTotalCharge()) + "</ EM><P>\n"; result += "On this rental you earned <EM>" + String.valueOf(aCustomer.getTotalFrequentRenterPoints()) + "</EM> frequent renter points<P>"; return result; } ~~~ 編譯并測試,然后繼續處理其他元素。我將逐一對各個元素進行上述過程。下面是整個重構完成后的結果: ~~~ class TextStatement … public String value(Customer aCustomer) { Enumeration rentals = aCustomer.getRentals(); String result = headerString(aCustomer); while (rentals.hasMoreElements()) { Rental each = (Rental) rentals.nextElement(); result += eachRentalString(each); } result += footerString(aCustomer); return result; } String eachRentalString (Rental aRental) { return "\t" + aRental.getMovie().getTitle()+ "\t" + String.valueOf(aRental.getCharge()) + "\n"; } String footerString (Customer aCustomer) { return "Amount owed is " + String.valueOf(aCustomer.getTotalCharge()) + "\n" + "You earned " + String.valueOf(aCustomer.getTotalFrequentRenterPoints()) + " frequent renter points"; } class HtmlStatement… public String value(Customer aCustomer) { Enumeration rentals = aCustomer.getRentals(); String result = headerString(aCustomer); while (rentals.hasMoreElements()) { Rental each = (Rental) rentals.nextElement(); result += eachRentalString(each); } result += footerString(aCustomer); return result; } String eachRentalString (Rental aRental) { return aRental.getMovie().getTitle()+ ": " + String.valueOf(aRental.getCharge()) + "<BR>\n"; } String footerString (Customer aCustomer) { return "<P>You owe <EM>" + String.valueOf(aCustomer.getTotalCharge()) + "</EM><P>" + "On this rental you earned <EM>" + String.valueOf(aCustomer.getTotalFrequentRenterPoints()) + "</EM> frequent renter points<P>"; } ~~~ 所有這些修改都完成后,兩個value() 函數看上去已經非常相似了,因此我可以使用Pull Up Method 將它們提升到superclass 中。提升完畢后,我需要在superclass 中把subclass 函數聲明為抽象函數。 ~~~ class Statement... public String value(Customer aCustomer) { Enumeration rentals = aCustomer.getRentals(); String result = headerString(aCustomer); while (rentals.hasMoreElements()) { Rental each = (Rental) rentals.nextElement(); result += eachRentalString(each); } result += footerString(aCustomer); return result; } abstract String headerString(Customer aCustomer); abstract String eachRentalString (Rental aRental); abstract String footerString (Customer aCustomer); ~~~ 然后我把TextStatement.value() 函數拿掉,編譯并測試。完成之后再把HtmlStatement.value() 也刪掉,再次編譯并測試。最后結果如圖11.2。 完成本重構后,處理其他種類的報表就容易多了:你只需為Statement 再建一個subclass ,并在其中覆寫(overrides)三個抽象函數即可。 ![](https://box.kancloud.cn/2016-08-15_57b1b5e79d1d5.gif) 圖11.2 Templae Method(模板函數)塑造完畢后的classes
                  <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>

                              哎呀哎呀视频在线观看