避免代码冗余,使用接口和泛型重构Java代码

转载自 避免代码冗余,使用接口和泛型重构Java代码

在使用动态语言和.NET工作了若干年后,我又回到老本行–Java开发。在Ruby中,清除代码冗余是非常方便的,而在Java中则需要结合接口和泛型实现类似的功能。

原始代码

以下是这个类中的一些方法用于后续的阐述。为了使例子更简洁,我移除了些代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
publicV get(finalK key)
{
  Session s;
  try{
      s = oGrid.getSession();
      ObjectMap map = s.getMap(cacheName);
      return(V) map.get(key);
  }
  catch(ObjectGridException oge)
  {
      thrownew RuntimeException("Error performing cache operation", oge);
  }
  finally
  {
      if(s != null)
          s.close();        
  }   
  returnnull;
}     
publicvoid put(finalK key, finalV value)
{
  Session s;
  try{
      s = oGrid.getSession();
      ObjectMap map = s.getMap(cacheName);
      map.upsert(key, value);
  }
  catch(ObjectGridException oge)
  {
      thrownew RuntimeException("Error performing cache operation", oge);
  }
  finally
  {
      if(s != null)
          s.close();            
  }           
}
publicMap<K, V> getAll(Set<? extendsK> keys)
{
  finalList<V> valueList = newArrayList<V>();
  finalList<K> keyList = newArrayList<K>();
  keyList.addAll(keys);
  Session s;
  try{
      s = oGrid.getSession();
      ObjectMap map = s.getMap(cacheName);
      valueList.addAll(map.getAll(keyList));
  }
  catch(ObjectGridException oge)
  {
      thrownew RuntimeException("Error performing cache operation", oge);
  }
  finally
  {
      if(s != null)
          s.close();            
  }
  Map<K, V> map = newHashMap<K, V>();
  for(inti = 0; i < keyList.size(); i++) {
      map.put(keyList.get(i), valueList.get(i));
  }
  returnmap;
}

遇到的问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Session s;
try{
  s = oGrid.getSession();
  ObjectMap map = s.getMap(cacheName);
  // Some small bit of business logic goes here
}
catch(ObjectGridException oge)
{
  thrownew RuntimeException("Error performing cache operation", oge);
}
finally
{
  if(s != null)
      s.close();            
}

上面的代码段几乎存在于类的每个方法中,这违反了DRY原则 。将来如果需要改变检索Session 和 ObjectMap实例的方式,或着某天这段代码被发现有缺陷,我们就不得不修改每个(包含这段代码的)方法,因此需要找到一种方式来复用这些执行代码。

重构后的代码

为了传递包含了原方法中业务逻辑的实例,我们创建一个带有抽象方法的 Executable 接口 。execute()方法参数为我们欲操作的ObjectMap实例。

1
2
3
interfaceExecutable<T> {
  publicT execute(ObjectMap map) throwsObjectGridException;
}

由于我们的目的仅仅是在每个方法中操作ObjectMap实例,可以创建executeWithMap()方法封装前述的那一大段重复代码。这个方法的参数是Executable接口的实例,实例包含着操作map的必要逻辑(译者注:这样Executable接口的实例中就是纯粹的业务逻辑,实现了解耦合)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
private<T> T executeWithMap(Executable<T> ex)
{
  Session s;
  try{
      s = oGrid.getSession();
      ObjectMap map = s.getMap(cacheName);
      // Execute our business logic
      returnex.execute(map);
  }
  catch(ObjectGridException oge)
  {
      thrownew RuntimeException("Error performing cache operation", oge);
  }
  finally
  {
      if(s != null)
          s.close();            
  }
}

现在,可以用如下形式的模板代码替换掉第一个例子中的代码:这个模板创建了一个匿名内部类,实现了Executable接口和execute()方法。其中execute()方法执行业务逻辑,并以getXXX()的方式返回结果(若为Void方法,返回null)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
publicV get(finalK key)
{
  returnexecuteWithMap(newExecutable<V>() {
      publicV execute(ObjectMap map) throwsObjectGridException
      {
          return(V) map.get(key);
      }
  });             
}     
publicvoid put(finalK key, finalV value)
{
  executeWithMap(newExecutable<Void>() {
      publicVoid execute(ObjectMap map) throwsObjectGridException
      {
          map.upsert(key, value);
          returnnull;
      }
  });             
}
publicMap<K, V> getAll(Set<? extendsK> keys)
{
  finalList<K> keyList = newArrayList<K>();
  keyList.addAll(keys);
  List<V> valueList = executeWithMap(newExecutable<List<V>>() {
      publicList<V> execute(ObjectMap map) throwsObjectGridException
      {
          returnmap.getAll(keyList);
      }
  });                             
  Map<K, V> map = newHashMap<K, V>();
  for(inti = 0; i < keyList.size(); i++) {
      map.put(keyList.get(i), valueList.get(i));
  }
  returnmap;
}

FunctionalInterface Annotation (功能接口注释)

Java 8 的 @FunctionalInterface annotation 使这一切变的简单。若某接口带有一个抽象方法,这个接口便可以被用作为lambda表达式的参数,称为功能接口。

1
2
3
4
@FunctionalInterface
interfaceExecutable<T> {
  publicT execute(ObjectMap map) throwsObjectGridException;
}

只要接口仅仅包含一个抽象方法,便可以使用这个annotation。这样就能减少相当数量的模板代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
publicV get(finalK key)
{
  returnexecuteWithMap((ObjectMap map) -> (V) map.get(key));
}     
publicvoid put(finalK key, finalV value)
{
  executeWithMap((ObjectMap map) -> { map.upsert(key, value); returnnull; });
}
publicMap<K, V> getAll(Set<? extendsK> keys)
{
  finalList<K> keyList = newArrayList<K>();
  keyList.addAll(keys);
  List<V> valueList = executeWithMap((ObjectMap map) -> map.getAll(keyList));
  Map<K, V> map = newHashMap<K, V>();
  for(inti = 0; i < keyList.size(); i++) {
      map.put(keyList.get(i), valueList.get(i));
  }
  returnmap;
}

结论

实现这些重构我很开心。它比原始的代码略复杂一点,但是更简明,更DRY,所以一切都是值得的。 尽管还有提升的空间,但这是一个良好的开始。

原文链接:  michaelbrameld  翻译:  ImportNew.com  ImportNew读者
译文链接:  http://www.importnew.com/6761.html

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

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

相关文章

一文理类加载相关知识:类加载器、双亲委派、SPI

思维导图 类加载的时机 类加载的流程 类从被加载到内存中开始&#xff0c;直到被从内存中卸载为止&#xff0c;它的整个生命周期包括&#xff1a;验证、准备、解析、初始化、使用和卸载7 个阶段。 其中验证、准备、解析 3 个部分统称为连接&#xff08;Linking&#xff09; …

可以搜python编程答案的软件_python实现百万答题自动百度搜索答案

用python搭建百万答题、自动百度搜索答案。 使用平台 windows7 python3.6 MIX2手机 代码原理 手机屏幕内容同步到pc端 对问题截图 对截图文字分析 用浏览器自动搜索文本 使用教程 1、使用Airdroid 将手机屏幕显示在电脑屏幕上。也可使用360手机助手实现。不涉及任何代码。实现效…

intellij idea设置主题、字体样式和背景色

转自&#xff1a; https://blog.csdn.net/fanrenxiang/article/details/80598895 点击这里查看 <intellij idea使用教程汇总篇> 引言&#xff1a;所谓工欲善其事必先利其器&#xff0c;idea就是这样的利器&#xff0c;刚装好的intellij idea主题样式是白的&#xff0c;…

MySQL优化(四):count()

count()不同写法的区别 COUNT(字段名)&#xff1a;返回SELECT语句检索的行中值不为NULL的行数 COUNT(1)&#xff1a;表示的是直接查询符合条件的数据库表的行数&#xff08;会包含值为NULL的行数&#xff09;。其中1指的是表中的第一个字段&#xff0c;如有表 table(id, colu…

图像sobel梯度详细计算过程_数字图像处理(第十章)

点、线、边缘检测背景知识。书中主要介绍了图像的一阶导数与二阶导数&#xff0c;这个之前的文章中有过介绍这里在复习一遍。对于函数 ,对于点 在x方向的一阶偏导为&#xff1a;,二阶偏导为&#xff1a;之后书中总结了一阶导与二阶导对于图像求取边缘的结论&#xff1a;孤立点检…

idea部署maven+javaweb项目到jboss

小编习惯使用eclipse对jboss跑的项目部署,第一次使用idea进行jboss部署项目,遇到很多问题,做此文章以帮助更多人. 图中涂鸦的是项目名,对应上自己的项目名即可 1.导入项目,这一步不多说 2.配置项目: a>点击file-->Project-Stucture-->Project 3.配置Modules 配置…

Java8-本地缓存

转载自 Java8-本地缓存这里我将会给大家演示用ConcurrentHashMap类和lambda表达式实现一个本地缓存。因为Map有一个新的方法可以在key为Null的时候自动计算一个新的value值。非常完美的实现cache。来看下代码&#xff1a;12345678910111213141516publicstatic void main(String…

Integer和Int的比较,谈谈拆卸和装箱

示例代码 public static void main(String[] args) {Integer a new Integer(10111);int b 10111;boolean equal1 a b;//自动拆箱&#xff0c;xxxValue()boolean equal2 a.equals(b);//自动装箱, valueOf()System.out.println(equal1);System.out.println(equal2); }反编译…

python调用webservice接口实例_python调用webservice接口的实现

使用suds这个第三方模块 from suds.client import Client url http://ip:port/?wsdl cilentClient(url) print cilent 查看webservice接口的具体信息&#xff1a; 调用接口方法&#xff0c;通常 client.service.methodname 实际测试过程中遇到的坑&#xff1a; 1、tns 值为Lo…

idea2021部署maven+javaweb项目到jboss(diy)

【README】 我为什么要写这个文章&#xff0c;看了这位老哥的博文 https://blog.csdn.net/PacosonSWJTU/article/details/118074604 部署成功了&#xff0c;很感谢&#xff0c;所以也想照做一下&#xff1b; 【1】创建web项目module &#xff08;Project02 是一个空项目&…

Java对象内存结构

转载自 Java对象内存结构学C/C出身的我&#xff0c;对Java有一点非常困惑&#xff0c;那就是缺乏计算对象占用内存大小的机制。而在C中就可以通过sizeof运算符来获得基本类型以及类实例的大小。C和C中的这个操作符对于指针运算、内存拷贝和IO操作都非常有用。 Java中并没有一个…

Java版大顶堆的实现

堆的概念 堆是一棵完全二叉树&#xff0c;一般使用数组来存储。通俗来讲堆其实就是利用数组来维护一个完全二叉树。 按照堆的特点可以把堆分为大顶堆和小顶堆 大顶堆&#xff1a;堆的每个结点的值都大于或等于其左右孩子结点的值 小顶堆&#xff1a;堆的每个结点的值都小于或…

Java 8新特性探究(二)深入解析默认方法

转载自 Java 8新特性探究&#xff08;二&#xff09;深入解析默认方法 什么是默认方法&#xff0c;为什么要有默认方法 简单说&#xff0c;就是接口可以有实现方法&#xff0c;而且不需要实现类去实现其方法。只需在方法名前面加个default关键字即可。 为什么要有这个特性&am…

把本地库推送到github远程库

【1】 github上创建远程库 注意 &#xff0c;远程库的名字要与本地库相同 【2】新建github远程库别名origin 【3】 代码提交 git add ./* &#xff1a; 把修改内容添加到暂存区 &#xff1b; git commit -m msg &#xff1a; 提交暂存区的修改内容到本地库&#xff1b; g…

react antd confirm content list_React造轮系列:对话框组件 - Dialog 思路

React造轮系列&#xff1a;对话框组件 - Dialog 思路对话框一般是我们点击按钮弹出的这么一个东西&#xff0c;主要类型有 Alter, Confirm 及 Modal, Modal 一般带有半透明的黑色背景。当然外观可参考 AntD 或者 Framework 等。确定 APIAPI 方面主要还是要参考同行&#xff0c;…

Spring IOC 和 AOP 概览

IOC&#xff08;控制反转&#xff09; IoC&#xff08;Inversion of Control&#xff0c;控制倒转&#xff09;。所谓IoC&#xff0c;对于spring框架来说&#xff0c;就是由spring来负责控制对象的生命周期和对象间的关系。 在没有IOC时&#xff0c;我们通过new 等关键字等方…

Java 并发实践 — ConcurrentHashMap 与 CAS

转载自 Java 并发实践 — ConcurrentHashMap 与 CAS最近在做接口限流时涉及到了一个有意思问题&#xff0c;牵扯出了关于concurrentHashMap的一些用法&#xff0c;以及CAS的一些概念。限流算法很多&#xff0c;我主要就以最简单的计数器法来做引。先抽象化一下需求&#xff1a;…

git rebase命令(转)

转自&#xff1a; https://www.yiibai.com/git/git_rebase.html git rebase命令在另一个分支基础之上重新应用&#xff0c;用于把一个分支的修改合并到当前分支。 使用语法 git rebase [-i | --interactive] [options] [--exec <cmd>] [--onto <newbase>][<u…

python tkinter计算器实例_python -Tkinter 实现一个小计算器功能

原博文 2017-03-25 22:08 − 文章来源&#xff1a;http://www.cnblogs.com/Skyyj/p/6618739.html 本代码是基于python 2.7的 如果是对于python3.X 则需要将 tkinter 改为Tkinter 将tkMessagebox&... 相关推荐 2019-12-10 15:59 − python GUI编程(Tkinter) Python 提供了多…

Spring IOC 容器启动、Bean生命周期详解

前言 在Spring IOC 和 AOP 概览中&#xff0c;简要介绍了IOC容器和AOP&#xff0c;没有深入IOC容器Bean的实例化&#xff0c;此文承接上文深入分析Bean的实例化过程、生命周期。 Spring IOC的过程 Spring的IoC容器在实现控制反转和依赖注入的过程中,可以划分为两个阶段: 容…