新秀翻譯(兩)——使用Java通用配置模板方法模式

假設你發現你已經非常重碼,你可能會考慮使用模板的方法來消除easy重復錯誤代碼。下面是一個示例:以下兩類,他完成了幾乎相同的功能:

  1. 實例化并初始化一個Reader來讀取CSV文件。
  2. 讀取每一行并解析;
  3. 把每一行的字符填充到Product或Customer對象;
  4. 將每個對象加入到Set里;
  5. 返回Set。


正如你看到的,僅僅有有凝視的地方是不一樣的。其它全部步驟都是同樣的。


ProductCsvReader.java

public class ProductCsvReader {Set<Product> getAll(File file) throws IOException {Set<Product> returnSet = new HashSet<>();try (BufferedReader reader = new BufferedReader(new FileReader(file))){String line = reader.readLine();while (line != null && !line.trim().equals("")) {String[] tokens = line.split("\\s*,\\s*");//不同Product product = new Product(Integer.parseInt(tokens[0]), tokens[1], new BigDecimal(tokens[2]));returnSet.add(product);line = reader.readLine();}}return returnSet;}
}

CustomerCsvReader.java

public class CustomerCsvReader {Set<Customer> getAll(File file) throws IOException {Set<Customer> returnSet = new HashSet<>();try (BufferedReader reader = new BufferedReader(new FileReader(file))){String line = reader.readLine();while (line != null && !line.trim().equals("")) {String[] tokens = line.split("\\s*,\\s*");//不同Customer customer = new Customer(Integer.parseInt(tokens[0]), tokens[1], tokens[2], tokens[3]);returnSet.add(customer);line = reader.readLine();}}return returnSet;}
}

對于本例來說,僅僅有兩個實體,可是一個真正的系統可能有幾十個實體,所以有非常多反復易錯的代碼。

你可能會發現Dao層有著同樣的情況。在每個Dao進行增刪改查的時候差點兒都是同樣的操作。唯一與不同的是實體和表。讓我們重構這些煩人的代碼吧。依據GoF設計模式第一部分提到的原則之中的一個,我們應該“封裝不同的概念“ProductCsvReader和CustomerCsvReader之間,不同的是有凝視的代碼。所以我們要做的是。把同樣的放到一個類。不同的抽取到還有一個類。我們先開始編寫ProductCsvReader,我們使用Extract Method提取帶凝視的部分:


ProductCsvReader.java after Extract Method

public class ProductCsvReader {Set<Product> getAll(File file) throws IOException {Set<Product> returnSet = new HashSet<>();try (BufferedReader reader = new BufferedReader(new FileReader(file))){String line = reader.readLine();while (line != null && !line.trim().equals("")) {String[] tokens = line.split("\\s*,\\s*");Product product = unmarshall(tokens);returnSet.add(product);line = reader.readLine();}}return returnSet;}Product unmarshall(String[] tokens) {Product product = new Product(Integer.parseInt(tokens[0]), tokens[1], new BigDecimal(tokens[2]));return product;}
}

如今我們已經把同樣(反復)的代碼和不同(各自特有)的代碼分開了,我們要創建一個父類AbstractCsvReader,它包括兩個類(ProductReader和CustomerReader)同樣的部分。我們把它定義為一個抽象類。由于我們不須要實例化它。然后我們將使用Pull Up Method重構這個父類。


AbstractCsvReader.java

abstract class AbstractCsvReader {Set<Product> getAll(File file) throws IOException {Set<Product> returnSet = new HashSet<>();try (BufferedReader reader = new BufferedReader(new FileReader(file))){String line = reader.readLine();while (line != null && !line.trim().equals("")) {String[] tokens = line.split("\\s*,\\s*");Product product = unmarshall(tokens);returnSet.add(product);line = reader.readLine();}}return returnSet;}
}

ProductCsvReader.java after Pull Up Method

public class ProductCsvReader extends AbstractCsvReader {Product unmarshall(String[] tokens) {Product product = new Product(Integer.parseInt(tokens[0]), tokens[1], new BigDecimal(tokens[2]));return product;}
}

假設在子類中沒有‘unmarshall’方法,該類就無法進行編譯(它調用unmarshall方法),所以我們要創建一個叫unmarshall的抽象方法


AbstractCsvReader.java with abstract unmarshall method

abstract class AbstractCsvReader {Set<Product> getAll(File file) throws IOException {Set<Product> returnSet = new HashSet<>();try (BufferedReader reader = new BufferedReader(new FileReader(file))){String line = reader.readLine();while (line != null && !line.trim().equals("")) {String[] tokens = line.split("\\s*,\\s*");Product product = unmarshall(tokens);returnSet.add(product);line = reader.readLine();}}return returnSet;}abstract Product unmarshall(String[] tokens);
}

如今。在這一點上,AbstractCsvReader是ProductCsvReader的父類,但不是CustomerCsvReader的父類。假設CustomerCsvReader繼承AbstractCsvReader編譯會報錯。為了解決問題我們使用泛型。


AbstractCsvReader.java with Generics

abstract class AbstractCsvReader<T> {Set<T> getAll(File file) throws IOException {Set<T> returnSet = new HashSet<>();try (BufferedReader reader = new BufferedReader(new FileReader(file))){String line = reader.readLine();while (line != null && !line.trim().equals("")) {String[] tokens = line.split("\\s*,\\s*");T element = unmarshall(tokens);returnSet.add(product);line = reader.readLine();}}return returnSet;}abstract T unmarshall(String[] tokens);
}

ProductCsvReader.java with Generics

public class ProductCsvReader extends AbstractCsvReader<Product> {@OverrideProduct unmarshall(String[] tokens) {Product product = new Product(Integer.parseInt(tokens[0]), tokens[1], new BigDecimal(tokens[2]));return product;}
}

CustomerCsvReader.java with Generics

public class CustomerCsvReader extends AbstractCsvReader<Customer> {@OverrideCustomer unmarshall(String[] tokens) {Customer customer = new Customer(Integer.parseInt(tokens[0]), tokens[1], tokens[2], tokens[3]);return customer;}
}

這就是我們要的!

不再有反復的代碼。父類中的方法是“模板”,它包括這不變的代碼。那些變化的東西作為抽象方法。在子類中實現。記住,當你重構的時候,你應該有自己主動化的單元測試來保證你不會破壞你的代碼。

我使用JUnit,你能夠使用我帖在這里的代碼,也能夠在這個Github庫找一些其它設計模式的樣例。在結束之前,我想說一下模板方法的缺點。模板方法依賴于繼承。患有?the Fragile Base Class Problem。簡單的說就是,改動父類會對繼承它的子類造成意想不到的不良影響。其實,基礎設計原則之中的一個的GoF設計模式提倡“多用組合少用繼承”。而且更多設計模式也告訴你怎樣避免代碼反復,同一時候又讓復雜或easy出錯的代碼盡量少的依賴繼承。歡迎交流,以便我能夠提高我的博客質量。


原文地址。Template Method Pattern Example Using Java Generics


翻譯的不好。歡迎拍磚。





本文轉自mfrbuaa博客園博客,原文鏈接:http://www.cnblogs.com/mfrbuaa/p/4657272.html,如需轉載請自行聯系原作者


本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/279365.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/279365.shtml
英文地址,請注明出處:http://en.pswp.cn/news/279365.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

框架基礎:深入理解Java注解類型(@Annotation)

注解的概念 注解的官方定義 首先看看官方對注解的描述&#xff1a; An annotation is a form of metadata, that can be added to Java source code. Classes, methods, variables, parameters and packages may be annotated. Annotations have no direct effect on the opera…

打印墨水調鋼筆墨水_如何節省墨水并改善網站打印質量

打印墨水調鋼筆墨水Printing out web pages you want a hard copy of can be a little hit and miss. Unlike other documents, it is not easy to tell exactly how many pieces of paper will be needed, and whether or not there will be any awkward clipping. Add to thi…

highcharts 怎么去掉鼠標懸停效果_練瑜伽減肥沒效果什么原因?

沒有心的參與&#xff0c;瑜伽就不是瑜伽曾經有很多人問&#xff1a;自己想用瑜伽來減肥&#xff0c;但練習瑜伽這么久&#xff0c;為什么還是減不下來&#xff1f;一點效果都沒有。瑜伽是什么&#xff1f;瑜伽只是一種單純的運動嗎&#xff1f;只讓身體參與進去就可以了嗎&…

百度地圖1

百度地圖BMap的類 BMap的屬性是一些構造函數,主大類有&#xff1a;核心類、基礎類、控件類、覆蓋物類、右鍵菜單類、地圖類型類、地圖吐槽類、服務類、全局類 核心類Map Map&#xff1a;最主要的一個類&#xff0c;集成了其他模塊的方法&#xff0c;是一個集成了整個地圖功能的…

Java基礎學習總結(23)——GUI編程

2019獨角獸企業重金招聘Python工程師標準>>> 一、AWT介紹 所有的可以顯示出來的圖形元素都稱為Component&#xff0c;Component代表了所有的可見的圖形元素&#xff0c;Component里面有一種比較特殊的圖形元素叫Container&#xff0c;Container(容器)在圖形界面里面…

spring-使用配置文件完成JdbcTemplate操作數據庫

一、創建spring項目項目名稱&#xff1a;spring101302二、在項目上添加jar包1.在項目中創建lib目錄/lib2.在lib目錄下添加spring支持commons-logging.jarjunit-4.10.jarlog4j.jarmysql-connector-java-5.1.18-bin.jarspring-beans-3.2.0.RELEASE.jarspring-context-3.2.0.RELEA…

瓦片經緯度及行列號轉換_Slippy map tilenames(瓦片和經緯度換算)

Slippy map tilenames(瓦片和經緯度換算)This article describes the file naming conventions for theSlippy Map application.Tiles are 256 256 pixel PNG filesEachzoom level is a directory, each column is a subdirectory, andeach tile in that column is a fileFilen…

在Windows 7或Vista(或Windows 8.x,Sorta)上禁用Aero

The Windows Aero Glass interface for Windows 7 or Vista requires a decent video card, you won’t be able to use it on an old clunker computer. For those worried about performance, sometimes squeezing every last drop requires disabling Aero. Windows 7或Vist…

一個簡單的JDBC通用工具

支持多種數據庫&#xff0c;統一方式產生連接&#xff0c;最優化、最簡單方式釋放資源。歡迎拍磚&#xff01;import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import java.sql.*; import java.util.List; import java.util.Properties…

sfm點云代碼_VisualSFM使用方法與心得

關于VisualSfM的更多內容組合多個模型(What if VisualSFM produces multiple models?)&#xff1a;按照上述步驟進行稀疏重建后&#xff0c;理論上可以得到很好的模型。如果結果產生了多個模型&#xff0c;要想把多個模型合成成一個&#xff0c;點擊菜單中的“SfM->More Fu…

macos mojave_使Ubuntu看起來像macOS Mojave的黑暗模式

macos mojaveIf you’re a Linux user who likes the look of the dark mode coming in macOS Mojave, you’re in luck: there’s a GTK theme just for you. 如果您是Linux用戶&#xff0c;并且喜歡macOS Mojave中的黑暗模式外觀&#xff0c;那么您很幸運&#xff1a;這里有一…

html的列表標簽

列表一般應用在布局中的新聞標題列表和文章標題列表以及網頁菜單等。 例如這個就是一個列表&#xff1a; 列表標簽有幾種&#xff0c;分別是有序列表&#xff0c;無序列表&#xff0c;定義列表。 有序列表<!DOCTYPE html> <html lang"en"> <head>&…

撬鎖錘怎么用_安全錘是啥?消防蜀黍教你怎么選?如何快速破拆逃生?

逃生錘又叫安全錘&#xff0c;生活中很多地方都可以看到&#xff0c;公交車、地鐵窗邊都少不了它們的身影它的款式也是五花八門&#xff0c;那么問題來了當遇到突發狀況被困車內時&#xff0c;哪種破窗工具最有效&#xff1f;又該如何快速逃生自救&#xff1f;近日&#xff0c;…

WSUS技術概覽

WSUS新功能展示: 支持更多微軟產品更新-->Windows Office MS SQL Server Exchange ......基于產品及分類篩選下載更新的能力更多語言支持定位更新目標計算機或計算機組的能力-->分發前,測試更新; 保護運行特定應用程序的計算機; 靈活使用Deadline; ...... 見下…

Java基礎學習總結(16)——Java制作證書的工具keytool用法總結

2019獨角獸企業重金招聘Python工程師標準>>> 一、keytool的概念 keytool 是個密鑰和證書管理工具。它使用戶能夠管理自己的公鑰/私鑰對及相關證書&#xff0c;用于&#xff08;通過數字簽名&#xff09;自我認證&#xff08;用戶向別的用戶/服務認證自己&#xff09…

什么是文件擴展名?

A file extension, or filename extension, is a suffix at the end of a computer file. It comes after the period, and is usually two-four characters long. If you’ve ever opened a document or viewed a picture, you’ve probably noticed these letters at the end…

變量與常量

什么是變量/常量&#xff1f; 變量是計算機內存中的一塊區域&#xff0c;變量可以存儲規定范圍內的值&#xff0c;而且值可以改變。基于變量的數據類型&#xff0c;解釋器會分配指定內存&#xff0c;并決定什么數據可以被存儲在內存中。常量是一塊只讀的內存區域&#xff0c;常…

python藍牙編程_藍牙編程經典程序!

文檔從網絡中收集&#xff0c;已重新整理排版.word版本可編輯.歡迎下載支持.1word版本可編輯.歡迎下載支持.L2CAP socketsExample 4-4. l2cap-server.c#include #include #include #include #include int main(int argc, char **argv){struct sockaddr_l2 loc_addr { 0 }, rem…

[項目總結]在ios中使用soundtouch庫實現變聲

這篇文章是項目總結了。 做了段時間的項目&#xff0c;過程中也遇到了很多麻煩&#xff0c;但是好在終于都解決了&#xff0c;這里是這里是項目之后憑著記憶總結出來&#xff0c;大家有遇到同樣的問題&#xff0c;希望能參考了&#xff0c;但是我記憶可能不太好了&#xff0c;要…

Myeclipse優化配置

2019獨角獸企業重金招聘Python工程師標準>>> 作為企業級開發最流行的工具&#xff0c;用Myeclipse開發java web程序無疑是最合適的&#xff0c;java web前端采用jsp來顯示&#xff0c;myeclipse默認打開jsp的視圖有卡頓的現象&#xff0c;那么如何更改jsp默認的打開…