您的位置:首页 > 其它

使用继承或接口实现模板方法的方式与函数回调的感悟

2017-06-02 10:56 866 查看

关于模板方法和函数回调的感悟

模板方法是将将一些方法公公共的操作提取出来的一种很好的方法,利用继承或接口的特性,再结合模板方法的的特性,我们在减少重复代码次数的情况下实现一批相关的方法。
下面通过两个例子,我们来感受和学习一下这种设计模式。


1.使用类继承实现

一般步骤:
1. 先写出解决该类事情其中 的一件的解决方案。
2. 分析代码,把会发生变化的代码抽取出来独立成一个方法。把该方法描述成一个抽象的方法。
3. 使用final修饰模板方法,防止别人 重写你的模板方法。


下面通过一个简单的小例子来说明一下,在这个需求中我们希望有一种方法能够计算其他任意方法的执行时间。
测试代码如下:


abstract class MyRuntime{

//实现计算某种方法代码执行的时间
public final void getTime(){
long startTime = System.currentTimeMillis();    //记录开始的时间
code();
long endTime = System.currentTimeMillis();  //记录结束的时间.
System.out.println("运行时间 :"+ (endTime-startTime));
}

//需要计算执行时间的代码,由子类继承实现
public abstract void code();
}

class Demo11 extends MyRuntime
{
public static void main(String[] args)
{
Demo11 d = new Demo11();
d.getTime();
}

//code方法内部就写要计算运行时间的代码;
public  void code(){
int i = 0;
while(i<100){
System.out.println("i="+i);
i++;
}

}
}


2. 使用接口实现


通过接口来实现模板方法时经常会与函数回调结合着使用,这里我们一以Spring中HibernateTemplate类实现的方法为例。
在HibernateTemplate中由于需要与数据库交互,所以每一个对数据库进行操作的方法都需要在执行之前获取绑定当前线程的Session,而在方法具体操作执行之后释放Session资源。基于这一原因,在HibernateTemplate类中就引用了模板模式和函数回调的思想。
下面,我们来看一下具体的代码。


public Serializable save(final Object entity) throws DataAccessException {
//方法执行的的第一步时调用executeWithNativeSession方法,并提供HibernateCallback接口中回调函数的实现
//executeWithNativeSession方法接收接口HibernateCallback,返回另一个函数doExecute
return executeWithNativeSession(new HibernateCallback<Serializable>() {
//HibernateCallback中抽象函数的实现,用来执行save方法特有的功能
@Override
public Serializable doInHibernate(Session session) throws HibernateException {
checkWriteOperationAllowed(session);
return session.save(entity);
}
});
}

简单说明:HibernateCallback  是一个接口,接口中有一个Abstract方法doInHibernate(Session session)

下面我们来看一下executeWithNativeSession方法的源代码:
public <T> T executeWithNativeSession(HibernateCallback<T> action) {
return doExecute(action, true);
}

可以发现executeWithNativeSession函数只是转而去执行doExecute(action, true)函数,我们在去看一下这个函数的代码:

protected <T> T doExecute(HibernateCallback<T> action, boolean enforceNativeSession) throws DataAccessException {
Assert.notNull(action, "Callback object must not be null");

Session session = null;
boolean isNew = false;
try {
//通过我们向Spring注入的SessionFactory工厂类,获取与当前线程绑定的Session,这是是为了实现事务功能
session = getSessionFactory().getCurrentSession();
}
catch (HibernateException ex) {
logger.debug("Could not retrieve pre-bound Hibernate session", ex);
}
if (session == null) {
session = getSessionFactory().openSession();
session.setFlushMode(FlushMode.MANUAL);
isNew = true;
}

try {
enableFilters(session);
Session sessionToExpose =
(enforceNativeSession || isExposeNativeSession() ? session : createSessionProxy(session));
//执行回调函数,去执行函数特有方法即session.save(entity);
return action.doInHibernate(sessionToExpose);
}
catch (HibernateException ex) {
throw SessionFactoryUtils.convertHibernateAccessException(ex);
}
catch (RuntimeException ex) {
// Callback code threw application exception...
throw ex;
}
//释放相关资源
finally {
if (isNew) {
SessionFactoryUtils.closeSession(session);
}
else {
disableFilters(session);
}
}
}

这样一来,HibernateTemplate类中的操作数据库的方法就都会执行  doExecute()方法,在该方法中获取Session以及释放资源,处理共有的操作,而且由于提供的HibernateCallback的实现类不同,在函数回调时就会执行自己特有的代码。


总结:其实上面所说回调,简单的可以说是,将自己的引用(接口实现类)作为参数传给别的方法,在别的方法里面,通过自己的引用(接口实现类)调用自己实现的方法。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐