模版方法(template method)模式

 一.模式简介

         下面是模板方法模式的结构图。直接把《设计模式》上的图拿过来用下:


        1) AbstractClass(抽象类):定义了一到多个的抽象方法,以供具体的子类来实现它们;而且还要实现一个模板方法,来定义一个算法的骨架。该模板方法不仅调用前面的抽象方法,也可以调用其他的操作,只要能完成自身的使命。

  2) ConcreteClass(具体类):实现父类中的抽象方法以完成算法中与特定子类相关的步骤。

          下面我们来实现下AbstractClass,因为还是有一些实现细节需要我们注意:

           

public abstract class AbstractClass {

	/*
	 * this template method should be declare as final
	 */
	final void templateMethod(){
		primitiveOperation1();
		primitiveOperation2();
		concreteOperation();
		hook();
	}

	/*
	 * a hook method, it's up to subclass to overrite it.
	 */
	private void hook() {}

	final void concreteOperation() {
		// TODO Auto-generated method stub
		
	}

	abstract void primitiveOperation2();

	abstract void primitiveOperation1();
}
注意:

        1.模版方法应该被声明为final的,也就是说避免子类的覆盖,导致算法顺序的改变。

        2.primitiveOperation1.2声明为了抽象类,有子类方法覆盖。

        3.hook()方法有空的或者默认的实现。hook的存在,可以让子类有能力对算法的不同点进行挂钩。要不要hook,由子类来决定。

二.模式的应用

       模版方法模式对于创建框架来说非常的有用,由框架来控制如何做事情,而由实现框架的人指定框架算法中每个具体的步骤。

       模版方法模式的标准模式被大量使用:
       1.Swing的JFrame
           JFrame是最基本的Swing容器,有一个paint()方法,默认状态下paint()是什么都不做的,因为它是一个hook,通过覆盖paint()方法,你可以讲自己的代码插入到JFrame中。
        2.Applet
          好吧,虽然applet已经没有人用了,但是他依旧是一个能说明模板方法模式的一个好例子,继承Applet类,你可以重写init(),start(), stop(),destroy(),paint()等方法。

        模板方法模式的非标准版也很多:
     1.Arrays.sort方法
      我们看一下sort方法的实现:       
 public static void sort(Object[] a) {
        Object[] aux = (Object[])a.clone();
        mergeSort(aux, a, 0, a.length, 0);
    }

private static void mergeSort(Object[] src,
				  Object[] dest,
				  int low,
				  int high,
				  int off) {
	int length = high - low;

	// Insertion sort on smallest arrays
        
            for (int i=low; i<high; i++)
                for (int j=i; j>low &&
			 ((Comparable) dest[j-1]).compareTo(dest[j])>0; j--)
                    swap(dest, j, j-1);
            return;
        
		// other condition implment
		}
          Arrays.sort方法只是一个辅助方法,用来做成对象的拷贝,真正的排序工作在mergeSort中完成,而mergeSort方法的冒泡排序操作依赖于compareTo()方法的实现来完成。
       假如我们需要给自定义的类型Apple的数组进行排序时,我们都知道,让Apple实现Comparable接口,然后实现该接口的compareTo()方法,从而完成排序操作。
        sort()方法的设计者希望这个方法能应用与所有的数组,但是我们无法设计一个类来继承java数组,所以他们定义了一个静态方法,而由被排序对象内的每个元素自行提供比较大小的算法部分。这虽然不是教科书上的模板方法模式,但仍然符合其精神。

        2.spring 中HibernateDaoSupport
         Spring 用另一种方式实现了 Template Method 模式,我们来详细解读一下。 Spring Hibernate 的调用提供了 HibernateDaoSupport 的支持,在该类中,有了一个 HibernateTemplate 类来调用 Hiebarnate 接口,通过另外一种方式使用 Template Method 模式,避免了开发者代码中出现诸如 Session 管理、事务控制等重复代码。

        现在我们看看Spring是如何做Template的,打开spring源代码发现在HibernateTemplate中包含execute(HibernateCallback action);该方法扮演的角色就是类似与上图中的AbstractClass类中的TemplateMothod.而该方法有只有一个唯一参数就是接口HibernateCallback所引用的对象action,在改接口抽象出了变化的数据库操作。 

public interface HibernateCallback {
    Object doInHibernate(Session session) throws HibernateException, SQLException;
}

就像我们在前面形容的一样HibernateCallback扮演一个钩子(hook的角色,这样用接口和不同的接口实现类替代了Template Method模式中的继承关系同时也将模板方法execute(HibernateCallback action)独立出来。

看看execute的实现:

public Object execute(HibernateCallback action, boolean exposeNativeSession) throws DataAccessException {
       Session session = getSession();
       boolean existingTransaction = SessionFactoryUtils.isSessionTransactional(session, getSessionFactory());
       if (existingTransaction) {
           logger.debug("Found thread-bound Session for HibernateTemplate");
       }
 
       FlushMode previousFlushMode = null;
       try {
           previousFlushMode = applyFlushMode(session, existingTransaction);
           Session sessionToExpose = (exposeNativeSession ? session : createSessionProxy(session));
           Object result = action.doInHibernate(sessionToExpose);
           flushIfNecessary(session, existingTransaction);
           return result;
       }
       catch (HibernateException ex) {
           throw convertHibernateAccessException(ex);
       }
       catch (SQLException ex) {
           throw convertJdbcAccessException(ex);
       }
       catch (RuntimeException ex) {
           // Callback code threw application exception...
           throw ex;
       }
       finally {
           if (existingTransaction) {
              logger.debug("Not closing pre-bound Hibernate Session after HibernateTemplate");
              if (previousFlushMode != null) {
                  session.setFlushMode(previousFlushMode);
              }
           }
           else {
              SessionFactoryUtils.releaseSession(session, getSessionFactory());
           }
       }
    }
 我们可以看到,在excute方法中做了对Session的管理和事务的控制,而代码:

Object result = action.doInHibernate(sessionToExpose);

则执行实际的数据库操作。

我们看看HibernateTemplatehibernate的一个get方法的封装:    

public Object get(final Class entityClass, final Serializable id, final LockMode lockMode)
           throws DataAccessException {
 
return execute(new HibernateCallback() {
           public Object doInHibernate(Session session) throws HibernateException {
              if (lockMode != null) {
                  return session.get(entityClass, id, lockMode);
              }
              else {
                  return session.get(entityClass, id);
              }
           }
       }, true);
    }
在该段代码中用匿名类声明了一个接口实现,并将改对象作为参数传给 excute 方法。如此,便实现了 Template Method 设计模式。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值