java 泛型示例_使用Java泛型的模板方法模式示例

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 泛型示例

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/340436.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

vue如何使浏览器url固定_怎么给 vue的 vue-router url地址最后加上 / 斜杠

这样没用 - -应该需要怎么加&#xff1f;router.beforeEach((to, from, next) > {if (!checkJs.getCookie(token) && to.path ! / && to.path ! /resetpassword) {next(/);} else if (checkJs.getCookie(token) && from.path /login || checkJs.ge…

oracle dbstart,dbstart: 未找到命令

oracle 12c在centos最小化下安装后&#xff0c;数据库不随机启动&#xff0c;按照网上的教程&#xff0c;编辑了/etc/oratab文件增加了rc.local文件结果还是不随机启动&#xff0c;通过&#xff1a;systemctl status rc-local.service可以看到服务启动失败&#xff0c;提示如标…

确定Java等价性的新时代?

几个月前&#xff0c;我读了一篇题为“确定Java等价性的新时代&#xff1f;”的博客文章。 这在某种程度上与我当时在我那令人脚的副项目Java :: Geci中开发的内容非常吻合 。 我建议您暂停阅读&#xff0c;阅读原始文章&#xff0c;然后再返回此处&#xff0c;即使您知道一定比…

oracle数据modeling分类,由浅入深 NoSQL的五种主流数据模型

【IT168 技术】本文内容是对《NoSQL Data Modeling Techniques》一文的简单概述&#xff0c;原文对NoSQL的几种数据模型进行了详细深入的讨论。是了解NoSQL数据模型不过错过的全面资料。NoSQL的一些非功能性的特性&#xff0c;比如扩展性、性能以及一致性的讨论&#xff0c;目前…

sklearn svm 调参_网舟科技 | 使用SVM模型进行分类预测时的参数调整技巧

原标题&#xff1a;网舟科技 | 使用SVM模型进行分类预测时的参数调整技巧SVM是一种在小样本低维度下比较适用的非线性建模方法&#xff0c;相对比其他常用的算法(比如决策树)&#xff0c;模型根据调参的好坏所表现的性能波动非常大。当我们决定使用SVM模型&#xff0c;模型的效…

dederss.php美国与,Dede经验:全站rss/连载和分类首页模板替换

我用的是Dedecms55 utf-8建的站。首先感谢开源工作者们的劳动&#xff0c;其次要感谢使用者写的N多问题与解答。我一个PHP初用者&#xff0c;能在一个月内&#xff0c;一个人把酷猫网http://www.92kcuat.com 建成今天这样&#xff0c;相信很多朋友都可以。当遇到问题时&#xf…

物联网协议之COAP简介及Java实践

目录 前言 一、COAP简介 1、关于COAP 2、COAP特点 3、基于COAP的NB-IoT接入流程 二、CoAP协议JAVA实践 1、californium介绍 2、Java集成 3、Maven 资源引入 4、定义Server端 5、Client调用 6、运行测试 总结 前言 今天平安夜&#xff0c;祝大家圣诞快乐&#xff0c…

遗传算法可用什么算法代替_获取可用密码算法的列表

遗传算法可用什么算法代替您如何了解可用的密码算法&#xff1f; Java规范列出了几种必需的密码&#xff0c;摘要等&#xff0c;但是提供程序通常提供的不止这些。 幸运的是&#xff0c;这很容易了解我们系统上的可用内容。 public class ListAlgorithms {public static void…

bp配置 sap_SAP转储订单之 STO without delivery

在《SAP转储订单STO小结》一文中&#xff0c;介绍了存转储订单(STO)的几种方式&#xff0c;在SAP Library中有相应的描述&#xff1a;1 Stock Transfer Between Plants in One Step2 Stock Transfer Between Plants in TwoSteps3 Stock Transport Order Without Delivery4 Stoc…

高效的企业测试–测试框架(5/6)

本系列文章的这一部分将介绍测试框架以及我在何时以及是否应用它们方面的想法和经验。 关于测试框架的思考 我对大多数测试框架不太满意的原因是&#xff0c;按照我的观点&#xff0c;它们大多增加了一些语法上的便利性和便利性&#xff0c;但本质上并不能解决拥有可维护的测…

linux 源码 目录,Linux系统主要目录及kernel源代码目录

1.在安装Linux后&#xff0c;先要了解清楚系统主要目录到底是干什么用的&#xff0c;避免以后再操作上的失误等。下面&#xff0c;就对Linux主要目录做一下简要说明&#xff1a;/boot&#xff1a;系统启动相关的文件&#xff0c;如内核、initrd&#xff0c;以及grub(bootloader…

[MEGA DEAL] 2020年完整的Java Master Class Bundle(96%)

通过超过62个小时的培训来掌握最流行的编程语言&#xff0c;从而树立良好的开发生涯 嘿&#xff0c;怪胎&#xff0c; 这一周&#xff0c;我们JCG促销专区 &#xff0c;我们有另一个极端的报价 。我们正在提供一个巨大的96&#xff05;off的完整2020 Python编程认证捆绑 。 立…

linux nc命令测试端口,Linux和Windows下的NC(Netcat)命令测试端口连通性

1、Linux OS 环境下(以Centos为例)&#xff0c;使用nc命令分别测试TCP和UDP端口连通性&#xff1a;css安装方法&#xff1a;nginx在客户端和服务器端分别安装nc工具&#xff0c;安装命令以下&#xff1a;webyum install nc1. Linux OS下使用nc命令&#xff0c;实现TCP方式监听服…

javafx css颜色_JavaFX技巧7:使用CSS颜色常量/派生颜色

javafx css颜色在使用FlexCalendarFX时&#xff0c;我不得不定义一组颜色以可视化不同颜色的不同日历的控件。 每个日历不仅提供一种颜色&#xff0c;还提供几种&#xff1a;用于取消选择/选定/悬停状态的背景和文本颜色。 颜色曾在多个地方使用过&#xff0c;但为了简洁起见&…

rowspan不显示 wpf_wpf的datagrid绑定datatable列不自动更新解决方案

wpf的datagrid绑定datatable列不自动更新描述如下&#xff1a;想利用程序实现显示NORTHWND.MDF中的所有表。listbox显示数据库中的表清单&#xff0c;选中listbox里面的一项以后&#xff0c;在datagrid中显示表的内容。xaml如下&#xff1a;Grid.Column"1" ItemsSour…

linux 查看端口 程序,linux开发:Linux下查看端口占用

前段时间有学生问到&#xff0c;怎么查看linux系统中已经被占用的端口&#xff1f;下面就统一给大家解释一下。提到端口&#xff0c;那首先来回顾端口定义&#xff0c;为了区分一台主机接收到的数据包应该转交给哪个任务来进行处理&#xff0c;使用端口号来区别&#xff1b;我们…

十进制小数化为二进制小数的方法是什么_八进制转换成十进制,十进制转换成八进制...

先来看八进制如何转换成十进制。其方法与二进制转换成十进制差不多&#xff1a;按权相加法&#xff0c;即将八进制每位上的数乘以位权&#xff08;如8,64,512….&#xff09;&#xff0c;然后将得出来的数再加在一起。如将72.45转换为十进制。如图1所示来看看十进制转八进制&am…

我两个月来对Quarkus的了解

又一年&#xff0c;另一个来临&#xff0c;我很荣幸再次开启围绕Java&#xff0c;语言&#xff0c;生态系统和朋友的24篇精彩博客文章的统治&#xff0c;这些博客文章将我们所有人带入了今年最安静的假期。 这已经是第五年了&#xff08;我只错过了2016年&#xff09;&#xff…

c++从字符串中提取数字求和_【函数应用】单元格文本内提取数字并求和

本篇的主题是将单元格内一串文本&#xff0c;找出所有数字并求和&#xff0c;如下图。难度较高&#xff0c;新手建议仅了解下&#xff0c;先学会数组运用&#xff0c;再研究此知识点。废话少说&#xff0c;步入正题。重点说明&#xff1a;本篇只针对文本内整数的数字进行提取并…

linux 网络端口全连接扫描,Linux系统下的网络端口扫描工具Nmap

Linux端口扫描工具nmap and nwatchPort scan简介port Scan的方法介绍 portScan就是一种通过检测对方服务器的开放端口&#xff0c;侦测对方服务器服务的方法。一般可分为主动式和被动式两种。主动式就是通过向对方服务器的特定端口发送数据包&#xff0c;根据应答来判断。以nma…