假设你发现你已经非常重码,你可能会考虑使用模板的方法来消除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,如需转载请自行联系原作者

新秀翻译(两)——使用Java通用配置模板方法模式相关推荐

  1. Java中的模板方法模式

    模板方法模式是一种行为模式,建议在超类中更一般地定义算法. 该算法是在称为模板方法的方法中定义的. 子类仅定义更具体的算法步骤的实现. 使用这种设计模式的好处是,算法后面的任何更改只会影响超类中的代码 ...

  2. Java设计模式之模板方法模式(UML类图分析+代码详解)

    大家好,我是一名在算法之路上不断前进的小小程序猿!体会算法之美,领悟算法的智慧~ 希望各位博友走过路过可以给我点个免费的赞,你们的支持是我不断前进的动力!! 加油吧!未来可期!! 本文将介绍java设 ...

  3. java 模板方法_设计模式(java实现)_模板方法模式(Template method)

    设计模式(java实现)_模板方法模式(Template method) 模板方法模式是编程中经常用到到的模式.它定义了一个操作中的算法骨架,将某些步骤延迟到子类中实现.这样,新的子类可以在不改变一个 ...

  4. Java 设计模式之模板方法模式

    一.了解模板方法模式 1.1 什么是模板方法模式 模板方法模式 Template Method Parrern)在一个方法中定义了一个算法的骨架,而将一些步骤延迟到子类中.模板方法使得子类可以在不改变 ...

  5. java设计模式 之 模板方法模式

    1.模板方法模式的定义: 定义一个操作中的算法的框架,而将一些步骤延迟到子类中.使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤. 2.模板方法模式的优点: ● 封装不变部分,扩展可变部 ...

  6. JAVA设计模式之--模板方法模式

    序言 在现实生活中,很多事情都包含几个实现步骤,例如请客吃饭,无论吃什么,一般都包含点单.吃东西.买单等几个步骤,通常情况下这几个步骤的次序是:点单 --> 吃东西 --> 买单.在这三个 ...

  7. 从西天取经的九九八十一难来看Java设计模式:模板方法模式

    模板方法模式 示例 模板方法模式 定义 意图 主要解决问题 适用场景 优缺点 西天取经的九九八十一难 示例 当我们设计一个类时,我们能明确它对外提供的某个方法的内部执行步骤, 但一些步骤,不同的子类有 ...

  8. Java设计模式之——模板方法模式

    Define the skeleton of an algorithm in an operation, deferring some steps to subclasses. Template Me ...

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

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

最新文章

  1. 【福利】Java 依然很牛逼!
  2. Leetcode 47. 全排列 II (每日一题 20211015)
  3. 分布式存储的集群可靠性计算(ceph)
  4. python STL分解
  5. html注释引用公共头部_HTML注释和引用
  6. python通过ssh配置交换机_配置(通过SSH)Cisco交换机的Python脚本
  7. 整型与布尔型的转换(信息学奥赛一本通-T1022)
  8. 在.NET中把项目从类库转为Web应用程序
  9. JAVA学习笔记-反射
  10. http status 400 – bad request 亚马逊_蛮拼的!这个亚马逊卖家为Prime Day做了这三大准备,销量暴涨58倍...
  11. 阿里Q3财报:阿里云连续第7个季度翻番
  12. Playwright之初体验
  13. 【第二届青训营-寒假前端场】- 「小游戏开发」笔记
  14. 「C++ MFC」 “多媒体定时器实例”讲解
  15. 『№20170501賽果確認』(5月9日晚上10:00分結束)
  16. K3s Load Balancer(Rancher LB)
  17. 【修改 ruoyi-plus 项目名字很麻烦,不如来试试这个工具!开源框架修改项目名!】
  18. 计算机科学与技术最轻松的工作,高薪又轻松的好工作排行榜 你的职业上榜了吗?...
  19. CocosCreator3D微信小游戏入门RunningBall(一): 物理
  20. 物联网实践|Huawei LiteOS开发环境搭建及在Hi3861上跑Demo

热门文章

  1. 使用泛型解决之前的问题
  2. 点云赋值 PointCloudT::Ptr 运行时崩溃
  3. sublime代码片段
  4. 专家观点:即使在云中 硬件同样至关重要
  5. Kinect for Windows SDK发布
  6. docker删除本地所有镜像
  7. docker镜像和容器区别
  8. mysql架构 视频_企业常见MySQL架构应用实战(高可用集群系统+调优经验)视频课程...
  9. 使用福禄克CFP单模光纤测试仪像专家一样设置参数!
  10. c语言构造数据类型有,《c语言程序设计基础7构造数据类型.ppt