java 泛型示例_使用Java泛型的模板方法模式示例
java 泛型示例
如果您發(fā)現(xiàn)除了某些部分外,您的許多例程完全相同,那么您可能需要考慮使用Template Method來消除容易出錯(cuò)的代碼重復(fù) 。 這是一個(gè)示例:下面是兩個(gè)做類似事情的類:
如您所見,只有在第三步中才有所不同-拆封到一個(gè)實(shí)體或另一個(gè)實(shí)體。 其他所有步驟均相同。 我已經(jīng)突出顯示了每個(gè)代碼段中代碼都不同的那一行。
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;} }在此示例中,只有兩個(gè)實(shí)體,但是實(shí)際系統(tǒng)中可能有數(shù)十個(gè)實(shí)體,因此有很多容易出錯(cuò)的重復(fù)代碼。 對(duì)于DAO,您可能會(huì)發(fā)現(xiàn)類似的情況,其中每個(gè)DAO的選擇,插入,更新和刪除操作將執(zhí)行相同的操作,僅適用于不同的實(shí)體和表。 讓我們開始重構(gòu)這個(gè)麻煩的代碼。 根據(jù)GoF設(shè)計(jì)模式第一部分中提到的一種設(shè)計(jì)原則,我們應(yīng)該“封裝變化的概念”。 在ProductCsvReader和CustomerCsvReader之間,突出顯示的代碼是不同的。 因此,我們的目標(biāo)是將變化的內(nèi)容封裝到單獨(dú)的類中,同時(shí)將保持不變的內(nèi)容移動(dòng)到單個(gè)類中。 讓我們首先開始只編輯一個(gè)類,即ProductCsvReader。 我們使用提取方法將行提取到自己的方法中:
提取方法后的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 = 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;} }既然我們已經(jīng)區(qū)分了哪些變化與哪些保持不變,我們將創(chuàng)建一個(gè)父類,該父類將保存兩個(gè)類保持相同的代碼。 我們將此父類稱為AbstractCsvReader。 讓我們使其抽象,因?yàn)闆]有理由單獨(dú)實(shí)例化該類。 然后,我們將使用Pull Up Method重構(gòu)將保持不變的方法移到該父類。
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
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;} }此類無法編譯,因?yàn)樗{(diào)用了在子類中找到的“ unmarshall”方法,因此我們需要?jiǎng)?chuàng)建一個(gè)稱為unmarshall的抽象方法。
使用抽象解組方法的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;}abstract Product unmarshall(String[] tokens); }現(xiàn)在,AbstractCsvReader將成為ProductCsvReader的出色父級(jí),而不是CustomerCsvReader的父級(jí)。 如果從AbstractCsvReader擴(kuò)展CustomerCsvReader,則它將不會(huì)編譯。 為了解決這個(gè)問題,我們使用泛型。
具有泛型的AbstractCsvReader.java
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
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與泛型
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;} }就是這樣! 沒有更多重復(fù)的代碼! 父類中的方法是“模板”,其中包含保持不變的代碼。 更改的內(nèi)容保留為抽象方法,這些方法在子類中實(shí)現(xiàn)。 請(qǐng)記住,重構(gòu)時(shí),應(yīng)該始終進(jìn)行自動(dòng)化的單元測(cè)試,以確保不破壞代碼。 我將JUnit用于我的。 您可以在Github存儲(chǔ)庫中找到我在此處發(fā)布的代碼以及其他一些“設(shè)計(jì)模式”示例。 在開始之前,我想簡(jiǎn)單介紹一下模板方法的缺點(diǎn)。 模板方法依賴于繼承,而繼承則存在脆弱的基類問題 。 簡(jiǎn)而言之,脆弱的基類問題描述了基類的更改如何被子類繼承,并經(jīng)常導(dǎo)致不良后果。 實(shí)際上,在GoF本書開始時(shí)發(fā)現(xiàn)的基本設(shè)計(jì)原則之一就是“偏向于繼承而不是繼承”,許多其他設(shè)計(jì)模式都說明了如何避免代碼重復(fù),復(fù)雜性或其他容易出錯(cuò)的代碼,而減少了依賴關(guān)于繼承。 請(qǐng)給我反饋,以便我可以繼續(xù)改進(jìn)我的文章。
翻譯自: https://www.javacodegeeks.com/2014/07/template-method-pattern-example-using-java-generics.html
java 泛型示例
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)總結(jié)
以上是生活随笔為你收集整理的java 泛型示例_使用Java泛型的模板方法模式示例的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何让老电脑焕发青春如何让老电脑焕发青春
- 下一篇: 确定Java等价性的新时代?