在日常开发中,经常在使用第三方的开源框架时,需要配置一些环境变量,然后正常的执行我们所有的方法,然后再进行一些资源回收的工作,如果每次在调用的过程中,我们都这么去设置,那冗余的代码就会很多。
通常我们会对这一类资源的调用采用工具类进行包装,例子如下:
/**
* 执行set操作
*
* @param key
* @param value
* @return
*/
public String set( String key,String value) {
ShardedJedis shardedJedis = null;
try {
// 从连接池中获取到jedis分片对象
shardedJedis = shardedJedisPool.getResource();
return shardedJedis.set(key, value);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (null != shardedJedis) {
// 关闭,检测连接是否有效,有效则放回到连接池中,无效则重置状态
shardedJedis.close();
}
}
return null;
}
/**
* 执行get操作
*
* @param key
* @param value
* @return
*/
public String get(String key) {
ShardedJedis shardedJedis = null;
try {
// 从连接池中获取到jedis分片对象
shardedJedis = shardedJedisPool.getResource();
return shardedJedis.get(key);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (null != shardedJedis) {
// 关闭,检测连接是否有效,有效则放回到连接池中,无效则重置状态
shardedJedis.close();
}
}
return null;
}
这个是对调用Redis的一个get/set方法的封装,从语法逻辑上看没什么问题,但是方法中存在很多相同的代码,最终执行的方法不同,类似于模板。下面讲解下怎么通过模板设计模式对这段代码进行封装。
1.新增一个接口,该接口包含一个回调方法
public interface Function<T, E> {
public T callback(E e);
}
说明:接口的第一个参数为目标执行方法的返回值,第二个参数为目标方法的句柄
2.模板方法,方法的参数是步骤1中的接口
private <T> T execute(Function<T, ShardedJedis> fun) {
ShardedJedis shardedJedis = null;
try {
// 从连接池中获取到jedis分片对象
shardedJedis = shardedJedisPool.getResource();
return fun.callback(shardedJedis);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (null != shardedJedis) {
// 关闭,检测连接是否有效,有效则放回到连接池中,无效则重置状态
shardedJedis.close();
}
}
return null;
}
说明:方法的参数为步骤1中的接口,在模板方法中编写好整个模板方法的步骤
3.真正需要调用的方法
public String set(final String key, final String value) {
return this.execute(new Function<String, ShardedJedis>() {
@Override
public String callback(ShardedJedis e) {
return e.set(key, value);
}
});
}
说明:调用步骤2中的方法,由于步骤2的入参是一个接口,所以默认实现一个匿名类接口,在接口中通过句柄调用真正要执行的方法。