java 泛型示例

如果您发现除了某些部分外,您的许多例程完全相同,那么您可能需要考虑使用Template Method来消除容易出错的代码重复 。 这是一个示例:下面是两个做类似事情的类:

  1. 实例化并初始化Reader以从CSV文件读取。
  2. 阅读每一行并将其分解为令牌。
  3. 将每行中的令牌解组到一个实体(产品或客户)中。
  4. 将每个实体添加到集合中。
  5. 返回集合。

如您所见,只有在第三步中才有所不同-拆封到一个实体或另一个实体。 其他所有步骤均相同。 我已经突出显示了每个代码段中代码都不同的那一行。

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。 我们使用提取方法将行提取到自己的方法中:

提取方法后的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;}
}

既然我们已经区分了哪些变化与哪些保持不变,我们将创建一个父类,该父类将保存两个类保持相同的代码。 我们将此父类称为AbstractCsvReader。 让我们使其抽象,因为没有理由单独实例化该类。 然后,我们将使用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

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的抽象方法。

使用抽象解组方法的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);
}

现在,AbstractCsvReader将成为ProductCsvReader的出色父级,而不是CustomerCsvReader的父级。 如果从AbstractCsvReader扩展CustomerCsvReader,则它将不会编译。 为了解决这个问题,我们使用泛型。

具有泛型的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;}
}

就是这样! 没有更多重复的代码! 父类中的方法是“模板”,其中包含保持不变的代码。 更改的内容保留为抽象方法,这些方法在子类中实现。 请记住,重构时,应该始终进行自动化的单元测试,以确保不破坏代码。 我将JUnit用于我的。 您可以在Github存储库中找到我在此处发布的代码以及其他一些“设计模式”示例。 在开始之前,我想简单介绍一下模板方法的缺点。 模板方法依赖于继承,而继承则存在脆弱的基类问题 。 简而言之,脆弱的基类问题描述了基类的更改如何被子类继承,并经常导致不良后果。 实际上,在GoF本书开始时发现的基本设计原则之一就是“偏向于继承而不是继承”,许多其他设计模式都说明了如何避免代码重复,复杂性或其他容易出错的代码,而减少了依赖关于继承。 请给我反馈,以便我可以继续改进我的文章。

翻译自: https://www.javacodegeeks.com/2014/07/template-method-pattern-example-using-java-generics.html

java 泛型示例

java 泛型示例_使用Java泛型的模板方法模式示例相关推荐

  1. java实现泛型检索_高级Java泛型:检索泛型类型参数

    java实现泛型检索 在JDK5中引入Java泛型之后, Java泛型Swift成为许多Java程序的组成部分. 但是,乍一看似乎很简单的Java泛型,程序员很快就会迷失此功能. 大多数Java程序员 ...

  2. Java的泛型特性_学习Java的重中之重!

    Java的"泛型"特性,你以为自己会了 使用Java的小伙伴,对于Java的一些高级特性一定再熟悉不过了,例如集合.反射.泛型.注解等等,这些可以说我们在平时开发中是经常使用到的, ...

  3. java 示例_功能Java示例 第3部分–不要使用异常来控制流程

    java 示例 这是称为" Functional Java by Example"的系列文章的第3部分. 我在本系列的每个部分中开发的示例是某种"提要处理程序" ...

  4. java 示例_最佳Java示例

    java 示例 什么是Java? (What is Java?) Java is a programming language developed by Sun Microsystems in 199 ...

  5. java pgp加密_基于Java Bouncy Castle的PGP加密解密示例

    # re: 基于Java Bouncy Castle的PGP加密解密示例  回复  更多评论 2016-03-02 10:32 by 毛小龙 对文件进行加密 在测试类里面已经跑通了 抽取出来调用就报这 ...

  6. java远控_基于java的远程控制 示例源码

    [实例简介]基于java的远程控制软件 [实例截图] 远程连接客户端如下: 服务端如下: [核心代码] package tcpudp; import java.awt.BorderLayout; im ...

  7. java ecc 加密_基于java实现的ECC加密算法示例

    本文实例讲述了基于java实现的ECC加密算法.分享给大家供大家参考,具体如下: ECC ECC-Elliptic Curves Cryptography,椭圆曲线密码编码学,是目前已知的公钥体制中, ...

  8. java核心教程_核心Java教程

    java核心教程 Welcome to Core Java Tutorial. I have written a lot on Core Java and Java EE frameworks. Th ...

  9. java se7 变化_[转] Java se 7新特性研究(二)

    今天主要研究Java se 7中异常处理的新功能.从今天开始正在将jdk7的说法改为java se 7跟oracle官网的一致 一.新增了try-with-resource 异常声明 在JDK7中只要 ...

  10. java初始化数据报_初始化java原因

    虚拟机的类加载机制 虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验.转换解析和初始化,最终形成可以被虚拟机直接使用的Java类 即虚拟机的类加载机制. 在Java中,类型的加载.链接 ...

最新文章

  1. jdk1.4容器类关系图
  2. Charles抓包https
  3. Python量化(八)下影线选股法
  4. pyecharts第十节、地图(二、中国地图)
  5. false-sharing原理浅析和测试
  6. 通俗易懂,CQRS概念浅析
  7. mysql 测试与mongodb 测试对比
  8. c++语言 自己构造函数 成员对象构造函数 调用顺序,C++类成员构造函数和析构函数顺序示例详细讲解...
  9. 画圆怎么编程python_简单实现python画圆功能
  10. oracle中制作副本,创建表的副本并在创建时为其提供约束
  11. 知名视频编辑工具:达芬奇剪辑调色软件 DaVinci Resolve Studio Mac v17.3.1
  12. 用matlab实现快速傅里叶变换的源程序,matlab快速傅里叶变换(三个matlab程序介绍)...
  13. 为什么谷歌浏览器打不开 Google Chrome打不开解决方法
  14. Element plus:将组件中英文转为中文
  15. 用Regedit命令控制注册表
  16. whois信息收集企业备案信息
  17. 基于jQuery发展历程时间轴特效代码
  18. 这是一篇系统的追热点方法论
  19. 电商网络推广是干什么,电商网络营销做什么
  20. java计算工龄_java计算工龄

热门文章

  1. 2018NOIP普及组初赛解析
  2. 动态规划训练18 [免费馅饼 HDU - 1176 ]
  3. ssh免密登陆失败原因总结(Linux)
  4. Hadoop入门(二十一)Mapreduce的求和程序
  5. Java IO: RandomAccessFile
  6. Java 线程池框架核心代码分析
  7. Maven精选系列--eclipse各种操作
  8. 关于Java你不知道的10件事
  9. java中的Queue队列的用法
  10. 20级、19级 | 一天一瞬间!【日更】